com.surelogic
Annotation Type UniqueInRegion


@Documented
@Target(value=FIELD)
public @interface UniqueInRegion

Declares that the field to which this annotation is applied is a unique reference to an object. Normally this indicates that the referenced object is not aliased. It is allowed, however, to pass a unique reference to a method as an actual argument or the receiver if formal argument or receiver, respectively, is Borrowed. That is, Unique values can be safely passed to the parameter or used as the receiver with the guarantee that they will still be unique when the method returns. Said another way we create a temporary alias on the stack then ensure that it goes away.

Setting the allowRead=true attribute weakens the uniqueness guarantees: it permits there to be @ReadOnly aliases around. In other words, only the ability to write (mutate) is restricted to this alias. Once a unique reference has granted allowRead, there is no going back, unlike with (temporary) borrowed references. This attribute is not currently checked by analysis.

This annotation differs from Unique only with regard to the region the state referenced by the annotated field is mapped into. This annotation declares that the Instance region of the object referenced by the annotated field is mapped into a named region of the object that contains the annotated field. Unique maps the state into the Instance region of the object that contains the annotated field if the field is final; into the field itself if the field is not final. Therefore, the two annotations below on the friends field are equivalent.

 @Unique
 private final Set<Person> friends = new HashSet<Person>();
 
 @UniqueInRegion("Instance")
 private final Set<Person> friends = new HashSet<Person>();
 
In addition, a more complex syntax where regions of the object referenced by the annotated field are allowed to be explicitly mapped to regions of the object that contains the annotated field. Using this syntax the annotation below is equivalent to the two previous examples.
 @UniqueInRegion("Instance into Instance")
 private final Set<Person> friends = new HashSet<Person>();
 
This syntax should be rare in practice, however we show an example of its use in the Examples section below.

In the case that the annotated field is non-final the field and the Instance region of the object referenced by the annotated field are mapped into a named region of the object that contains the annotated field. This situation is illustrated in the code below.

 @Region("private ContactData")
 class ContactData {
 
   @UniqueInRegion("ContactData")
   private final Set<Person> friends = new HashSet<Person>()
   
   @UniqueInRegion("ContactData")
   private Set<Person> family = new HashSet<Person>()
   ...
 }
 
In this example, the non-final family field is mapped into the ContactData region but final friends field is not. The state referenced by both fields is mapped into the ContactData region.

Semantics:

At all times, the value of the annotated field is either null or is an object that is not referenced by a field of any other object or another field of the same object. The Instance region (and any named regions if the more complex into syntax is used) of the object referenced by the annotated field is mapped into a named region of the object that contains the annotated field.

In the case that the annotated field is non-final the field and the Instance region (and any named regions if the more complex into syntax is used) of the object referenced by the annotated field are mapped into a named region of the object that contains the annotated field.

Examples:

The below class defines a region, called ObserverRegion, that includes the integer notifyCounter and the state referenced by the observers field (i.e., the internals of the HashSet object).
 @Region("private ObserverRegion")
 class Observer {
 
   @InRegion("ObserverRegion")
   private int notifyCounter = 0;
 
   @UniqueInRegion("ObserverRegion")
   private final Set<Callback> observers = new HashSet<Callback>()
   ...
 }
 
The same result can be accomplished with the more complex syntax shown in the example below. However, in this case the more complex syntax is not recommended.
 @Region("private ObserverRegion")
 class Observer {
 
   @InRegion("ObserverRegion")
   private int notifyCounter = 0;
 
   @UniqueInRegion("Instance into ObserverRegion")
   private final Set<Callback> observers = new HashSet<Callback>()
   ...
 }
 
The more complex syntax is necessary if only a portion of a referenced object is to be aggregated is more complex. Consider the highly contrived example below.
 @Regions({
   @Region("private OrderRegion"),
   @Region("private InvRegion") })
 @RegionLocks({
   @RegionLock("ShopLock is this protects OrderRegion"),
   @RegionLock("InvLock  is inv  protects InvRegion") })
 public class Shop {
 
   @InRegion("OrderRegion")
   private int ordersPlaced;
 
   private static class SandwichInventory {
     int bread;
     int mustard;
     int ordersPlaced;
   }
 
   @UniqueInRegion("bread into InvRegion, mustard into InvRegion, ordersPlaced into OrderRegion, Instance into Instance")
   private final SandwichInventory inv = new SandwichInventory();
 
   void order() {
     synchronized (inv) {
       inv.bread++;
       inv.mustard++;
     }
     synchronized (this) {
       ordersPlaced++;
       inv.ordersPlaced++;
     }
   }
   ...
 }
 
In the above example the fields that count the number of orders placed are protected by synchronizing on this while the inventory fields ( bread and mustard) are protected by synchronizing on inv. All the state of the SandwichInventory must be placed into named regions (even if you never use one of the named regions, e.g., you create a JunkRegion) and the aggregation must be completed with a mapping of the region Instance of the referenced object, usually Instance into Instance. Finally, it is important in this example that the field inv is declared to be final—otherwise the field itself would have to be mapped into each of the named regions, which, in this case, would be illegal because while inv could be mapped into InvRegion or OrderRegion, it cannot be mapped into both.

Models of the sort shown for the Shop class above are discouraged and should occur rarely in Java code that follows object-oriented design principles.

Javadoc usage notes:

This annotation may placed in Javadoc, which can be useful for Java 1.4 code which does not include language support for annotations, via the @annotate tag.
 /**
  * @annotate Region("private ObserverRegion")
  */
 class Observer {
 
   /**
    * @annotate InRegion("ObserverRegion")
    */
   private int notifyCounter = 0;
 
   /**
    * @annotate UniqueInRegion("ObserverRegion")
    */
   private final Set<Callback> observers = new HashSet<Callback>()
   ...
 }
 

See Also:
Region, Unique

Required Element Summary
 String value
          The value of this attribute must conform to the following grammar (in Augmented Backus–Naur Form):
 
Optional Element Summary
 boolean allowRead
          Setting the this attribute to true weakens the uniqueness guarantees: it permits there to be @ReadOnly aliases of the referenced object.
 

Element Detail

value

public abstract String value
The value of this attribute must conform to the following grammar (in Augmented Backus–Naur Form):
 value = regionSpecification / regionMapping *("," regionMapping)
 
 regionMapping = simpleRegionSpecification "into" regionSpecification
 
 regionSpecification = simpleRegionSpecificaion / qualifiedRegionName
 
 simpleRegionSpecification = IDENTIFIER                         ; Region of the class being annotated
 
 qualifedRegionName = IDENTIFIER *("." IDENTIFIER) : IDENTIFER  ; Static region from the named, optionally qualified, class
 
 IDENTIFIER = Legal Java Identifier
 

In A into B, the first RegionSpecification is relative to the object referenced by the field; the second is relative to the object that contains the field.

allowRead

public abstract boolean allowRead
Setting the this attribute to true weakens the uniqueness guarantees: it permits there to be @ReadOnly aliases of the referenced object. In other words, only the ability to write (mutate) is restricted to this alias. This attribute is not currently checked by analysis.

Default:
false


Copyright © 2012 Surelogic, Inc.. All Rights Reserved.