001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026: package org.cougaar.core.component;
027:
028: import java.io.Serializable;
029: import java.net.URL;
030: import java.util.Comparator;
031:
032: /**
033: * An immutable description of a loadable component (for example,
034: * a plugin, servlet, etc).
035: * <p>
036: * We may want several levels of description and protection,
037: * starting here and ending up at an uninitialized instance.
038: * This could be done either as a sequence of classes or
039: * as a single class with instantiation state (e.g. Description,
040: * Classloaded, Instantiated, Loaded (into a component), Active).
041: * <p>
042: * The Description is interpreted and evaluated to varying degrees
043: * as it is passed through the hierarchy until the insertion point
044: * is found. In particular, the description will be evaluated for
045: * trust attributes at each level before instantiation or pass-through.
046: * <p>
047: **/
048: public final class ComponentDescription implements Serializable {
049:
050: /** Higher priority than internal components. Containers are
051: * less likely to accomodate this level than the others
052: **/
053: public final static int PRIORITY_HIGH = 1;
054: /** Same priority as internal subcomponents. E.g. loaded
055: * before binders.
056: **/
057: public final static int PRIORITY_INTERNAL = 2;
058: /** Binders are typically loaded before subcomponents **/
059: public final static int PRIORITY_BINDER = 3;
060: /** Standard subcomponent (including plugin) priority **/
061: public final static int PRIORITY_COMPONENT = 4;
062: /** Load after standard subcomponents **/
063: public final static int PRIORITY_LOW = 5;
064:
065: /** Default priority for ComponentDescription objects **/
066: public final static int PRIORITY_STANDARD = PRIORITY_COMPONENT;
067:
068: /** return a priority value, given a priority string which is one of HIGH, INTERNAL, BINDER, COMPONENT,
069: * LOW, or STANDARD.
070: **/
071: public final static int parsePriority(String s) {
072: if ("HIGH".equals(s))
073: return PRIORITY_HIGH;
074: if ("INTERNAL".equals(s))
075: return PRIORITY_INTERNAL;
076: if ("BINDER".equals(s))
077: return PRIORITY_BINDER;
078: if ("COMPONENT".equals(s))
079: return PRIORITY_COMPONENT;
080: if ("LOW".equals(s))
081: return PRIORITY_LOW;
082: if ("STANDARD".equals(s))
083: return PRIORITY_STANDARD;
084:
085: throw new IllegalArgumentException("Unknown priority string \""
086: + s + "\"");
087: }
088:
089: /** return a priority string given a legal priority value **/
090: public final static String priorityToString(int p) {
091: if (p == PRIORITY_HIGH)
092: return "HIGH";
093: if (p == PRIORITY_INTERNAL)
094: return "INTERNAL";
095: if (p == PRIORITY_BINDER)
096: return "BINDER";
097: if (p == PRIORITY_COMPONENT)
098: return "COMPONENT";
099: if (p == PRIORITY_LOW)
100: return "LOW";
101: throw new IllegalArgumentException("Unknown priority value "
102: + p);
103: }
104:
105: private final String name;
106: private final String insertionPoint;
107: private final String classname;
108: private final URL codebase;
109: private final Object parameter;
110: private final Object certificate;
111: private final Object lease;
112: private final Object policy;
113: private final int priority;
114:
115: /**
116: * A ComponentDescription must have a non-null name,
117: * insertionPoint, and classname.
118: *
119: * @throws IllegalArgumentException if name is null,
120: * insertionPoint is null, or classname is null.
121: */
122: public ComponentDescription(String name, String insertionPoint,
123: String classname, URL codebase, Object parameter,
124: Object certificate, Object lease, Object policy) {
125: this (name, insertionPoint, classname, codebase, parameter,
126: certificate, lease, policy, PRIORITY_STANDARD);
127: }
128:
129: /**
130: * A ComponentDescription must have a non-null name,
131: * insertionPoint, and classname.
132: *
133: * @throws IllegalArgumentException if name is null,
134: * insertionPoint is null, classname is null, or
135: * priority is illegal.
136: */
137: public ComponentDescription(String name, String insertionPoint,
138: String classname, URL codebase, Object parameter,
139: Object certificate, Object lease, Object policy,
140: int priority) {
141: this .name = name;
142: this .insertionPoint = insertionPoint;
143: this .classname = classname;
144: this .codebase = codebase;
145: this .parameter = parameter;
146: this .certificate = certificate;
147: this .lease = lease;
148: this .policy = policy;
149: if (priority < PRIORITY_HIGH || priority > PRIORITY_LOW) {
150: throw new IllegalArgumentException(
151: "Invalid priority specification");
152: } else {
153: this .priority = priority;
154: }
155:
156: // clone the object parameters to ensure immutability?
157:
158: // validate -- also see "readObject(..)"
159: if (name == null) {
160: throw new IllegalArgumentException("Null name");
161: } else if (insertionPoint == null) {
162: throw new IllegalArgumentException("Null insertionPoint");
163: } else if (classname == null) {
164: throw new IllegalArgumentException("Null classname");
165: }
166: }
167:
168: /**
169: * The name of a particular component, used
170: * both as the displayable identifier of
171: * the Component and to disambiguate between
172: * multiple similar components which might otherwise
173: * appear equal. <p>
174: * It would be consistent to treat the name as a UID/OID for
175: * a specific component.
176: **/
177: public String getName() {
178: return name;
179: }
180:
181: /**
182: * The point in the component hierarchy where the component
183: * should be inserted. It is used by the component hierarchy to
184: * determine the container component the plugin should be
185: * added. This point is interpreted individually by each
186: * (parent) component as it propagates through the container
187: * hierarchy - it may be interpreted any number of times along
188: * the way to the final insertion point. <p>
189: * example: a plugin would have an insertion point of
190: * "Node.AgentManager.Agent.PluginManager.Plugin"
191: * <p>
192: * Note that data formats (including presentation methods) may
193: * abbreviate full insertion paths as relative to some parent
194: * in the context. For instance, agent.ini files may refer to
195: * plugins as ".PluginManager.Plugin".
196: */
197: public String getInsertionPoint() {
198: return insertionPoint;
199: }
200:
201: /**
202: * The name of the class to instantiate, relative to the
203: * codebase url. The class will not be loaded or instantiated
204: * until the putative parent component has been found and has
205: * had the opportunity to verify the plugin's identity and
206: * authorization.
207: **/
208: public String getClassname() {
209: return classname;
210: }
211:
212: /**
213: * Where the code for classname should be loaded from.
214: * Will be evaulated for trust before any classes are loaded
215: * from this location.
216: **/
217: public URL getCodebase() {
218: return codebase;
219: }
220:
221: /**
222: * A parameter supplied to the component immediately
223: * after construction by calling <pre>instance.setParameter(param);</pre>
224: * using reflection.
225: * <p>
226: * setParameter will be called IFF the parameter is non-null. It is an error
227: * for a ComponentDescription to specify a non-null parameter, but for the
228: * actual Component to not define the setParameter method:
229: * <pre>
230: * public void setParameter(Object parameter);
231: * </pre>
232: * <p>
233: * A parameter is often some sort of structured object (xml document, etc).
234: * While is is defined as just an Object, most implementations
235: * impose additional restrictions (e.g. Serializable)
236: * for safety reasons.
237: **/
238: public Object getParameter() {
239: return parameter;
240: }
241:
242: /**
243: * Assurance that the Plugin is trustworth enough to instantiate.
244: * The type is specified as Object until we decide what really
245: * should be here.
246: **/
247: public Object getCertificate() {
248: return certificate;
249: }
250:
251: /**
252: * Lease information - how long should the plugin live in the agent?
253: * We need some input on what this should look like.
254: * It is possible that this could be merged with Policy.
255: **/
256: public Object getLeaseRequested() {
257: return lease;
258: }
259:
260: /**
261: * High-level Policy information. Allows plugin policy/techspec
262: * to contribute to the component hookup process before it is
263: * actually instantiated. Perhaps this is overkill, and instance-level
264: * policy is sufficient.
265: **/
266: public Object getPolicy() {
267: return policy;
268: }
269:
270: /** Load Priority of the component in it's Container relative to
271: * other child components loaded at the same time at the same Containment point.
272: * Two components loaded at the same point and time with the same priority
273: * will be loaded in the order they are specified in.
274: * <p>
275: * However, it is up to the Container how to interpret priority. Priority is,
276: * in general, only a recommendation, although the standard Containers
277: * implement the recommended interpretation.
278: * <p>
279: * In particular, Containers may decline to load high-priority subcomponents
280: * as early as they might like.
281: * <p>
282: * Note that code should always use the priority constants, rather than
283: * int values, as the actual values and implementations are subject to change
284: * without notice.
285: **/
286: public int getPriority() {
287: return priority;
288: }
289:
290: /**
291: * Equality tests <i>all</i> publicly visibile fields.
292: * <p>
293: * In the future this may be modified to ignore the
294: * certificate, lease, and/or policy.
295: * @note Priority is not considered when testing components for priority.
296: */
297: public boolean equals(Object o) {
298: if (o == this ) {
299: return true;
300: }
301: if (!(o instanceof ComponentDescription)) {
302: return false;
303: }
304: ComponentDescription cd = (ComponentDescription) o;
305: // simplistic equality test:
306: if (eq(name, cd.name) && eq(insertionPoint, cd.insertionPoint)
307: && eq(classname, cd.classname)
308: && eq(codebase, cd.codebase)
309: && eq(parameter, cd.parameter)
310: && eq(certificate, cd.certificate)
311: && eq(lease, cd.lease) && eq(policy, cd.policy)) {
312: return true;
313: }
314: return false;
315: }
316:
317: private final static boolean eq(Object a, Object b) {
318: return ((a == null) ? (b == null) : (a.equals(b)));
319: }
320:
321: public int hashCode() {
322: return (name.hashCode() ^ insertionPoint.hashCode() ^ classname
323: .hashCode());
324: }
325:
326: private void readObject(java.io.ObjectInputStream ois)
327: throws java.io.IOException, ClassNotFoundException {
328: ois.defaultReadObject();
329: // validate -- see constructor
330: if (name == null) {
331: throw new java.io.InvalidObjectException("Null name");
332: } else if (insertionPoint == null) {
333: throw new java.io.InvalidObjectException(
334: "Null insertionPoint");
335: } else if (classname == null) {
336: throw new java.io.InvalidObjectException("Null classname");
337: }
338: }
339:
340: public String toString() {
341: return "<ComponentDescription " + classname
342: + ((parameter == null) ? "" : (" " + parameter)) + ">";
343: }
344:
345: private static final long serialVersionUID = 1673609926074089996L;
346:
347: /** A comparator which may be used for sorting ComponentDescriptions by priority **/
348: public final static Comparator PRIORITY_Comparator = new Comparator() {
349: public final int compare(Object a, Object b) {
350: return (((ComponentDescription) b).priority - ((ComponentDescription) a).priority);
351: }
352: };
353:
354: }
|