Privileged API
From APIDesign
(New page: When designing a library and its API, you often do not talk only to one audience of users, but to multiple groups. For example one group shall be allowed to create objects, other group...) |
|||
(One intermediate revision not shown.) | |||
Line 1: | Line 1: | ||
When designing a library and its [[API]], you often do not talk only to one audience of users, but to multiple groups. For example one group shall be allowed to create objects, other group shall just query their state. In some sense the first group has more privileges, just like a server administrator can change content of a website, while regular uses can only view its [[HTML]] pages. | When designing a library and its [[API]], you often do not talk only to one audience of users, but to multiple groups. For example one group shall be allowed to create objects, other group shall just query their state. In some sense the first group has more privileges, just like a server administrator can change content of a website, while regular uses can only view its [[HTML]] pages. | ||
- | This topic has been deeply discussed in section ''Give the Creator of an Object More Rights'' in [[Chapter 5]]. You can also listen to [[API Design Tips]] podcast dedicated to [[Privileged API]]: [[Image:Apitip03-constructor-and-competition.mp3]] | + | This topic has been deeply discussed in section ''Give the Creator of an Object More Rights'' in [[Chapter 5]]. You can also listen to [[API Design Tips]] podcast dedicated to [[Privileged API]]: [[Image:Apitip03-constructor-and-competition.mp3]], [[Media:Apitip03-constructor-and-competition.mp3|download]]. |
+ | == Use Constructor or [[Factory]] Methods == | ||
+ | The basic trick to achieve privileged mode is to force initialization of certain attributes of an object only during its creation and prevent changing them later. As an example consider a simple lock implementation: | ||
+ | <source lang="java" snippet="mutex.api"/> | ||
+ | The ''withLock'' method takes a ''Runnable'' which ensures that everyone who acquires the lock also releases it. This is more suitable method for public consumption in [[Cluelessness]] mode then pair of ''lock''/''unlock'' methods. One just cannot forget to ''unlock'': | ||
+ | |||
+ | <source lang="java" snippet="mutex.use"/> | ||
+ | |||
+ | However (and we found that in [[NetBeans]] [[API]]s), when used frequently there may be too many temporary ''Runnable'' objects being created. This may hurt performance and as such one may want the ''lock''/''unlock'' pair of methods to be available to those who can be trusted to use it correctly. This can be done with following addition to the [[API]]: | ||
+ | |||
+ | <source lang="java" snippet="mutex.privileged.api"/> | ||
+ | |||
+ | The ''Privileged'' class then serves as a handle which the creator of the ''Mutex'' instance may keep (private) reference to: | ||
+ | |||
+ | <source lang="java" snippet="mutex.init"/> | ||
+ | |||
+ | and use it for privileged access (as the field is not accessible to public use), while everyone else can access only the safe methods (as the ''Mutex'' field is publicly exposed in the [[API]]). So creator can call: | ||
+ | |||
+ | <source lang="java" snippet="mutex.privileged"/> | ||
+ | |||
+ | Regular users have to rely on old good and safe ''withLock''. | ||
+ | |||
+ | === Everyone Can Become Privileged === | ||
+ | |||
+ | Please note that the author of a [[Privileged API]] does not assign roles to users of own [[API]] in advance. There are no ultimately ''privileged'' users knowing some special ''token'' to use the library in special mode. There are no library ''adminstrators'' that could log into a web server and manage its [[HTML]] pages. Initially, when approaching a [[Privileged API]] everyone is treated equally. Everyone can create anything. However those who create an object of such [[API]] can become ''privileged'' gaining special access to that object instance (but not to other instances). | ||
+ | |||
+ | In the context of previous ''Mutex'' example it means that everyone can create new instance of ''Mutex'' (using the privileged constructor) and re-expose such instance in own [[API]]. However by keeping the ''Privileged'' instance private, the right to act as privileged user with respect to the one instance of the ''Mutex'' remains restricted to its creator (plus those who are given the ''Privileged'' instance as a shared token by some side-ways). | ||
+ | |||
+ | This is one way to create [[API]] for privileged use. There are other as discussed in [[Chapter 5]]. | ||
+ | |||
+ | <comments/> | ||
[[Category:APIDesignPatterns]] [[Category:APIDesignPatterns:Creational]] | [[Category:APIDesignPatterns]] [[Category:APIDesignPatterns:Creational]] |
Current revision
When designing a library and its API, you often do not talk only to one audience of users, but to multiple groups. For example one group shall be allowed to create objects, other group shall just query their state. In some sense the first group has more privileges, just like a server administrator can change content of a website, while regular uses can only view its HTML pages.
This topic has been deeply discussed in section Give the Creator of an Object More Rights in Chapter 5. You can also listen to API Design Tips podcast dedicated to Privileged API: , download.Use Constructor or Factory Methods
The basic trick to achieve privileged mode is to force initialization of certain attributes of an object only during its creation and prevent changing them later. As an example consider a simple lock implementation:
Code from Mutex.java:
See the whole file.public final class Mutex { Lock lock = new ReentrantLock(); public Mutex() { } public void withLock(Runnable r) { try { lock.lock(); r.run(); } finally { lock.unlock(); } } }
The withLock method takes a Runnable which ensures that everyone who acquires the lock also releases it. This is more suitable method for public consumption in Cluelessness mode then pair of lock/unlock methods. One just cannot forget to unlock:
Code from MutexTest.java:
See the whole file.class R implements Runnable { int cnt; public void run() { cnt++; } } R r = new R(); MUTEX.withLock(r); assertEquals("Counter increased", 1, r.cnt);
However (and we found that in NetBeans APIs), when used frequently there may be too many temporary Runnable objects being created. This may hurt performance and as such one may want the lock/unlock pair of methods to be available to those who can be trusted to use it correctly. This can be done with following addition to the API:
Code from Mutex.java:
See the whole file.public Mutex(Privileged privileged) { if (privileged.mutex != null) { throw new IllegalStateException(); } privileged.mutex = this; } public static final class Privileged { private Mutex mutex; public void lock() { mutex.lock.lock(); } public void unlock() { mutex.lock.unlock(); } }
The Privileged class then serves as a handle which the creator of the Mutex instance may keep (private) reference to:
Code from MutexTest.java:
See the whole file.private static final Mutex.Privileged PRIVILEGED = new Mutex.Privileged(); public static final Mutex MUTEX = new Mutex(PRIVILEGED);
and use it for privileged access (as the field is not accessible to public use), while everyone else can access only the safe methods (as the Mutex field is publicly exposed in the API). So creator can call:
Code from MutexTest.java:
See the whole file.try { PRIVILEGED.lock(); // do the operation cnt++; } finally { PRIVILEGED.unlock(); } assertEquals("Counter increased", 1, cnt);
Regular users have to rely on old good and safe withLock.
Everyone Can Become Privileged
Please note that the author of a Privileged API does not assign roles to users of own API in advance. There are no ultimately privileged users knowing some special token to use the library in special mode. There are no library adminstrators that could log into a web server and manage its HTML pages. Initially, when approaching a Privileged API everyone is treated equally. Everyone can create anything. However those who create an object of such API can become privileged gaining special access to that object instance (but not to other instances).
In the context of previous Mutex example it means that everyone can create new instance of Mutex (using the privileged constructor) and re-expose such instance in own API. However by keeping the Privileged instance private, the right to act as privileged user with respect to the one instance of the Mutex remains restricted to its creator (plus those who are given the Privileged instance as a shared token by some side-ways).
This is one way to create API for privileged use. There are other as discussed in Chapter 5.
<comments/>