001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.openide;
043:
044: import java.beans.Introspector;
045: import java.beans.PropertyChangeListener;
046: import java.beans.PropertyChangeSupport;
047: import java.io.IOException;
048: import java.io.ObjectInputStream;
049: import java.io.ObjectOutputStream;
050: import java.io.Serializable;
051: import java.util.Collection;
052: import java.util.Enumeration;
053: import java.util.List;
054: import java.util.logging.Level;
055: import java.util.logging.Logger;
056: import org.openide.util.Enumerations;
057: import org.openide.util.Exceptions;
058: import org.openide.util.HelpCtx;
059: import org.openide.util.Lookup;
060:
061: /** This class represents an abstract subclass for services
062: * (compilation, execution, debugging, etc.) that can be registered in
063: * the system.
064: *
065: * @author Jaroslav Tulach
066: * @deprecated The prefered way to register and lookup services
067: * is now {@link Lookup} as described in <a href="util/doc-files/api.html#lookup">
068: * services registration and lookup</a> page.
069: */
070: @Deprecated
071: public abstract class ServiceType extends Object implements
072: Serializable, HelpCtx.Provider {
073: /** generated Serialized Version UID */
074: private static final long serialVersionUID = -7573598174423654252L;
075:
076: /** Name of property for the name of the service type. */
077: public static final String PROP_NAME = "name"; // NOI18N
078: private static final Logger err = Logger
079: .getLogger("org.openide.ServiceType"); // NOI18N
080:
081: /** name of the service type */
082: private String name;
083:
084: /** listeners support */
085: private transient PropertyChangeSupport supp;
086:
087: /** Default human-presentable name of the service type.
088: * In the default implementation, taken from the bean descriptor.
089: * @return initial value of the human-presentable name
090: * @see java.beans.FeatureDescriptor#getDisplayName
091: */
092: protected String displayName() {
093: try {
094: return Introspector.getBeanInfo(getClass())
095: .getBeanDescriptor().getDisplayName();
096: } catch (Exception e) {
097: // Catching IntrospectionException, but also maybe NullPointerException...?
098: Logger.getLogger(ServiceType.class.getName()).log(
099: Level.WARNING, null, e);
100:
101: return getClass().getName();
102: }
103: }
104:
105: /** Method that creates a cloned instance of this object. Subclasses
106: * are encouraged to implement the {@link Cloneable}
107: * interface, in such case the <code>clone</code> method is called as a result
108: * of calling this method. If the subclass does not implement
109: * <code>Cloneable</code>, it is serialized and deserialized,
110: * thus new instance created.
111: *
112: * @return new instance
113: * @exception IllegalStateException if something goes wrong, but should not happen
114: * @deprecated Service instance files should instead be copied in order to clone them.
115: */
116: @Deprecated
117: public final ServiceType createClone() {
118: Exception anEx;
119:
120: if (this instanceof Cloneable) {
121: try {
122: return (ServiceType) clone();
123: } catch (CloneNotSupportedException ex) {
124: anEx = ex;
125: }
126: } else {
127: try {
128: org.openide.util.io.NbMarshalledObject m = new org.openide.util.io.NbMarshalledObject(
129: this );
130:
131: return (ServiceType) m.get();
132: } catch (IOException ex) {
133: anEx = ex;
134: } catch (ClassNotFoundException ex) {
135: anEx = ex;
136: }
137: }
138:
139: // the code can get here only if an exception occured
140: // moreover it should never happen that this code is executed
141: IllegalStateException ex = new IllegalStateException();
142:
143: ex.initCause(anEx);
144: Exceptions.attachLocalizedMessage(ex, "Cannot createClone for "
145: + this ); // NOI18N
146:
147: throw ex;
148: }
149:
150: /** Correctly implements the clone operation on this object. In
151: * order to work really correctly, the subclass has to implement the
152: * Cloneable interface.
153: *
154: * @return a new cloned instance that does not have any listeners
155: * @deprecated Service instance files should instead be copied in order to clone them.
156: */
157: @Deprecated
158: protected Object clone() throws CloneNotSupportedException {
159: ServiceType t = (ServiceType) super .clone();
160:
161: // clear listeners
162: t.supp = null;
163:
164: // clear name
165: t.name = null;
166:
167: return t;
168: }
169:
170: /** Set the name of the service type.
171: * Usually it suffices to override {@link #displayName},
172: * or just to provide a {@link java.beans.BeanDescriptor} for the class.
173: * @param name the new human-presentable name
174: */
175: public void setName(String name) {
176: String old = this .name;
177: this .name = name;
178:
179: if (supp != null) {
180: supp.firePropertyChange(PROP_NAME, old, name);
181: }
182: }
183:
184: /** Get the name of the service type.
185: * The default value is given by {@link #displayName}.
186: * @return a human-presentable name for the service type
187: */
188: public String getName() {
189: return (name == null) ? displayName() : name;
190: }
191:
192: /** Get context help for this service type.
193: * @return context help
194: */
195: public abstract HelpCtx getHelpCtx();
196:
197: /** Add a property change listener.
198: * @param l the listener to add
199: */
200: public final synchronized void addPropertyChangeListener(
201: PropertyChangeListener l) {
202: if (supp == null) {
203: supp = new PropertyChangeSupport(this );
204: }
205:
206: supp.addPropertyChangeListener(l);
207: }
208:
209: /** Remove a property change listener.
210: * @param l the listener to remove
211: */
212: public final void removePropertyChangeListener(
213: PropertyChangeListener l) {
214: if (supp != null) {
215: supp.removePropertyChangeListener(l);
216: }
217: }
218:
219: /** Fire information about change of a property in the service type.
220: * @param name name of the property
221: * @param o old value
222: * @param n new value
223: */
224: protected final void firePropertyChange(String name, Object o,
225: Object n) {
226: if (supp != null) {
227: supp.firePropertyChange(name, o, n);
228: }
229: }
230:
231: /**
232: * The registry of all services. This class is provided by the NetBeans core
233: * and should hold all of the services registered to the system.
234: * <P>
235: * This class can be serialized to securely save settings of all
236: * services in the system.
237: * @deprecated Use lookup instead.
238: */
239: @Deprecated
240: public static abstract class Registry implements Serializable {
241: /** suid */
242: final static long serialVersionUID = 8721000770371416481L;
243:
244: /** Get all available services managed by the engine.
245: * @return an enumeration of {@link ServiceType}s
246: */
247: public abstract Enumeration<ServiceType> services();
248:
249: /** Get all available services that are assignable to the given superclass.
250: * @param clazz the class that all services should be subclass of
251: * @return an enumeration of all matching {@link ServiceType}s
252: */
253: public <T extends ServiceType> Enumeration<T> services(
254: final Class<T> clazz) {
255: class IsInstance implements
256: Enumerations.Processor<ServiceType, T> {
257: public T process(ServiceType obj, Collection ignore) {
258: return clazz.isInstance(obj) ? clazz.cast(obj)
259: : null;
260: }
261: }
262:
263: return Enumerations.filter(services(), new IsInstance());
264: }
265:
266: /** Getter for list of all service types.
267: * @return a list of {@link ServiceType}s
268: */
269: public abstract List getServiceTypes();
270:
271: /** Setter for list of service types. This permits changing
272: * instances of the objects but only within the types that are already registered
273: * in the system by manifest sections. If an instance of any other type
274: * is in the list it is ignored.
275: *
276: * @param arr a list of {@link ServiceType}s
277: * @deprecated Better to change service instance files instead.
278: */
279: @Deprecated
280: public abstract void setServiceTypes(List arr);
281:
282: /** Find the service type implemented as a given class.
283: * The whole registry is searched for a service type of that exact class (subclasses do not count).
284: * <P>
285: * This could be used during (de-)serialization
286: * of a service type: only store its class name
287: * and then try to find the type implemented by that class later.
288: *
289: * @param clazz the class of the service type looked for
290: * @return the desired type or <code>null</code> if it does not exist
291: * @deprecated Just use lookup.
292: */
293: @Deprecated
294: public ServiceType find(Class clazz) {
295: Enumeration en = services();
296:
297: while (en.hasMoreElements()) {
298: Object o = en.nextElement();
299:
300: if (o.getClass() == clazz) {
301: return (ServiceType) o;
302: }
303: }
304:
305: return null;
306: }
307:
308: /** Find a service type of a supplied name in the registry.
309: * <P>
310: * This could be used during (de-)serialization
311: * of a service type: only store its name
312: * and then try to find the type later.
313: *
314: * @param name (display) name of service type to find
315: * @return the desired type or <code>null</code> if it does not exist
316: */
317: public ServiceType find(String name) {
318: Enumeration en = services();
319:
320: while (en.hasMoreElements()) {
321: ServiceType o = (ServiceType) en.nextElement();
322:
323: if (name.equals(o.getName())) {
324: return o;
325: }
326: }
327:
328: return null;
329: }
330: }
331:
332: /** Handle for a service type. This is a serializable class that should be used
333: * to store types and to recreate them after deserialization.
334: * @deprecated The prefered way to register and lookup services
335: * is now {@link Lookup} as described in <a href="util/doc-files/api.html#lookup">
336: * services registration and lookup</a> page.
337: */
338: @Deprecated
339: public static final class Handle extends Object implements
340: java.io.Serializable {
341: /** generated Serialized Version UID */
342: static final long serialVersionUID = 7233109534462148872L;
343:
344: /** name executor */
345: private String name;
346:
347: /** name of class of the executor */
348: private String className;
349:
350: /** kept ServiceType may be <tt>null</tt> after deserialization */
351: private transient ServiceType serviceType;
352:
353: /** Create a new handle for an service.
354: * @param ex the service to store a handle for
355: */
356: public Handle(ServiceType ex) {
357: name = ex.getName();
358: className = ex.getClass().getName();
359: serviceType = ex;
360: }
361:
362: /** Find the service for this handle.
363: * @return the reconstituted service type, or <code>null</code> in case of problems
364: */
365: public ServiceType getServiceType() {
366: if (serviceType == null) {
367: // the class to search for
368: Class<? extends ServiceType> clazz;
369:
370: // the first subclass of ServiceType to search for
371: Class<?> serviceTypeClass;
372:
373: // try to find it by class
374: try {
375: serviceTypeClass = Class.forName(className, true,
376: Lookup.getDefault().lookup(
377: ClassLoader.class));
378: clazz = serviceTypeClass
379: .asSubclass(ServiceType.class);
380:
381: while (serviceTypeClass.getSuperclass() != ServiceType.class) {
382: serviceTypeClass = serviceTypeClass
383: .getSuperclass();
384: }
385: } catch (ClassNotFoundException ex) {
386: // #32140 - do not notify user about this exception. This exception
387: // should be only thrown when module providing the service
388: // was uninstalled and in that case the exception must be ignored.
389: err.log(Level.FINE, "Service not found", ex); //NOI18N
390:
391: // nothing better to use
392: clazz = ServiceType.class;
393: serviceTypeClass = ServiceType.class;
394: }
395:
396: // try to find the executor by name
397: ServiceType.Registry r = Lookup.getDefault().lookup(
398: ServiceType.Registry.class);
399: Enumeration en = r.services(clazz);
400: ServiceType some = r.find(clazz);
401:
402: while (en.hasMoreElements()) {
403: ServiceType t = (ServiceType) en.nextElement();
404:
405: if (!serviceTypeClass.isInstance(t)) {
406: // ignore non instances
407: continue;
408: }
409:
410: String n = t.getName();
411:
412: if ((n != null) && n.equals(name)) {
413: return t;
414: }
415:
416: // remember it for later use
417: if ((some == null)
418: || ((some.getClass() != clazz) && (t
419: .getClass() == clazz))) {
420: // remember the best match
421: some = t;
422: }
423: }
424:
425: // if clazz does not exist and there is no service with same name -> return null
426: if (serviceTypeClass == ServiceType.class) {
427: return null;
428: }
429:
430: return some;
431: }
432:
433: return serviceType;
434: }
435:
436: /** Old compatibility version.
437: */
438: private void readObject(ObjectInputStream ois)
439: throws IOException, ClassNotFoundException {
440: name = (String) ois.readObject();
441:
442: String clazz = (String) ois.readObject();
443: className = (clazz == null) ? null
444: : org.openide.util.Utilities.translate(clazz);
445: }
446:
447: /** Has also save the object.
448: */
449: private void writeObject(ObjectOutputStream oos)
450: throws IOException {
451: oos.writeObject(name);
452: oos.writeObject(className);
453: }
454:
455: // for debugging purposes
456: public String toString() {
457: return "Handle[" + className + ":" + name + "]"; // NOI18N
458: }
459: }
460: }
|