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.netbeans.core;
043:
044: import java.io.IOException;
045: import java.io.ObjectInputStream;
046: import java.io.ObjectOutputStream;
047: import java.util.ArrayList;
048: import java.util.Collection;
049: import java.util.Collections;
050: import java.util.Enumeration;
051: import java.util.HashMap;
052: import java.util.Iterator;
053: import java.util.LinkedList;
054: import java.util.List;
055: import java.util.Map;
056: import java.util.Map.Entry;
057: import java.util.logging.Level;
058: import java.util.logging.Logger;
059: import org.openide.ServiceType;
060: import org.openide.cookies.InstanceCookie;
061: import org.openide.filesystems.FileObject;
062: import org.openide.loaders.DataFolder;
063: import org.openide.loaders.DataObject;
064: import org.openide.loaders.DataObjectNotFoundException;
065: import org.openide.loaders.InstanceDataObject;
066: import org.openide.util.Lookup;
067: import org.openide.util.LookupEvent;
068: import org.openide.util.LookupListener;
069: import org.openide.util.io.NbMarshalledObject;
070:
071: /** Works with all service types.
072: *
073: * @author Jaroslav Tulach
074: * @deprecated Obsoleted by lookup and new settings system.
075: */
076: @SuppressWarnings({"deprecation","unchecked"})
077: public final class Services extends ServiceType.Registry implements
078: LookupListener {
079: /** serial */
080: static final long serialVersionUID = -7558069607307508327L;
081:
082: /** Result containing all current services. */
083: private Lookup.Result<ServiceType> allTypes;
084:
085: /** Mapping between service name and given ServiceType instance. */
086: private Map<String, ServiceType> name2Service;
087:
088: /** Default instance */
089: public static Services getDefault() {
090: return (Services) Lookup.getDefault().lookup(
091: org.openide.ServiceType.Registry.class);
092: }
093:
094: public Services() {
095: name2Service = new HashMap<String, ServiceType>();
096: }
097:
098: public ServiceType find(Class clazz) {
099: return (ServiceType) Lookup.getDefault().lookup(clazz);
100: }
101:
102: /** Override to specially look up no-op services. */
103: public ServiceType find(String name) {
104: Map<String, ServiceType> lookupMap = name2Service;
105: ServiceType ret;
106: synchronized (lookupMap) {
107: ret = lookupMap.get(name);
108: }
109:
110: if (ret == null) {
111: ret = super .find(name);
112: synchronized (lookupMap) {
113: lookupMap.put(name, ret);
114: }
115: }
116:
117: return ret;
118: }
119:
120: /** Result containing all current services. */
121: private Lookup.Result<ServiceType> getTypesResult() {
122: boolean init = false;
123: synchronized (this ) {
124: if (allTypes == null) {
125: allTypes = Lookup.getDefault().lookupResult(
126: ServiceType.class);
127: allTypes.addLookupListener(this );
128: init = true;
129: }
130: }
131: if (init)
132: resultChanged(null);
133: return allTypes;
134: }
135:
136: /** A change in lookup occured.
137: * @param ev event describing the change
138: */
139: public void resultChanged(LookupEvent ev) {
140: synchronized (name2Service) {
141: name2Service.clear();
142: }
143: }
144:
145: /** Getter for list of all services types.
146: * @return list of ServiceType
147: */
148: public java.util.List<ServiceType> getServiceTypes() {
149: return new ArrayList<ServiceType>(getTypesResult()
150: .allInstances());
151: }
152:
153: /** Setter for list of all services types. This allows to change
154: * instaces of the objects but only of the types that are already registered
155: * to the system by manifest sections.
156: *
157: * @param arr list of ServiceTypes
158: */
159: public synchronized void setServiceTypes(
160: java.util.List/*<ServiceType>*/arr0) {
161: if (arr0 == null) {
162: throw new NullPointerException();
163: }
164:
165: @SuppressWarnings("unchecked")
166: java.util.List<ServiceType> arr = ensureSingleness((java.util.List<ServiceType>) arr0);
167:
168: HashMap<ServiceType, DataObject> services = new HashMap<ServiceType, DataObject>(
169: 20); // <service type, DataObject>
170: searchServices(NbPlaces.getDefault().findSessionFolder(
171: "Services").getPrimaryFile(), services); // NOI18N
172:
173: // storing services
174: HashMap<DataFolder, List<DataObject>> order = new HashMap<DataFolder, List<DataObject>>(
175: 10); // <parent folder, <file>>
176: Iterator<ServiceType> it = arr.iterator();
177: while (it.hasNext()) {
178: ServiceType st = it.next();
179: DataObject dobj = services.get(st);
180:
181: if (dobj != null) {
182: // store existing
183: try {
184: dobj = InstanceDataObject.create(dobj.getFolder(),
185: dobj.getPrimaryFile().getName(), st, null);
186: } catch (IOException ex) {
187: Logger.getLogger(Services.class.getName()).log(
188: Level.WARNING, null, ex);
189: }
190: services.remove(st);
191: } else {
192: dobj = storeNewServiceType(st);
193: }
194:
195: // compute order in folders
196: if (dobj != null) {
197: DataFolder parent = dobj.getFolder();
198: List<DataObject> orderedFiles = order.get(parent);
199: if (orderedFiles == null) {
200: orderedFiles = new ArrayList<DataObject>(6);
201: order.put(parent, orderedFiles);
202: }
203: orderedFiles.add(dobj);
204: }
205: }
206:
207: // storing order attribute
208: for (Entry<DataFolder, List<DataObject>> entry : order
209: .entrySet()) {
210: DataObject parent = entry.getKey();
211: List<DataObject> orderedFiles = entry.getValue();
212: if (orderedFiles.size() < 2)
213: continue;
214:
215: Iterator<DataObject> files = orderedFiles.iterator();
216: StringBuffer orderAttr = new StringBuffer(64);
217: while (files.hasNext()) {
218: DataObject file = files.next();
219: orderAttr.append(file.getPrimaryFile().getNameExt())
220: .append('/');
221: }
222: orderAttr.deleteCharAt(orderAttr.length() - 1);
223: try {
224: parent.getPrimaryFile().setAttribute(
225: "OpenIDE-Folder-Order", orderAttr.toString()); // NOI18N
226: } catch (IOException ex) {
227: Logger.getLogger(Services.class.getName()).log(
228: Level.WARNING, null, ex);
229: }
230: }
231:
232: // remove remaining services from default FS
233: for (DataObject dobj : services.values()) {
234: try {
235: dobj.delete();
236: } catch (IOException ex) {
237: Logger.getLogger(Services.class.getName()).log(
238: Level.WARNING, null, ex);
239: }
240: }
241:
242: }
243:
244: private DataObject storeNewServiceType(ServiceType st) {
245: Class stype = st.getClass();
246: // finds direct subclass of service type
247: while (stype.getSuperclass() != ServiceType.class) {
248: stype = stype.getSuperclass();
249: }
250:
251: try {
252: String folder = org.openide.util.Utilities
253: .getShortClassName(stype);
254:
255: DataFolder dfServices = NbPlaces.getDefault()
256: .findSessionFolder("Services"); // NOI18N
257: DataFolder dfTarget = DataFolder.create(dfServices, folder);
258:
259: return InstanceDataObject.create(dfTarget, null, st, null);
260: } catch (Exception ex) {
261: Logger.getLogger(Services.class.getName()).log(
262: Level.WARNING, null, ex);
263: return null;
264: }
265: }
266:
267: /** ensure that instance of the service type will be listed just once.
268: */
269: private List<ServiceType> ensureSingleness(List<ServiceType> l) {
270: List<ServiceType> newList = new ArrayList<ServiceType>(l.size());
271:
272: for (ServiceType stype : l) {
273: if (newList.contains(stype)) {
274: continue;
275: } else {
276: newList.add(stype);
277: }
278: }
279:
280: return newList;
281: }
282:
283: /** search all data objects containing service type instance. */
284: private void searchServices(FileObject folder,
285: Map<ServiceType, DataObject> services) {
286: FileObject[] fobjs = folder.getChildren();
287: for (int i = 0; i < fobjs.length; i++) {
288: if (!fobjs[i].isValid())
289: continue;
290: if (fobjs[i].isFolder()) {
291: searchServices(fobjs[i], services);
292: } else {
293: try {
294: DataObject dobj = DataObject.find(fobjs[i]);
295: InstanceCookie inst = (InstanceCookie) dobj
296: .getCookie(InstanceCookie.class);
297:
298: if (inst == null)
299: continue;
300: if (instanceOf(inst, ServiceType.class)) {
301: ServiceType ser = (ServiceType) inst
302: .instanceCreate();
303:
304: services.put(ser, dobj);
305: }
306: } catch (DataObjectNotFoundException ex) {
307: } catch (Exception ex) {
308: Logger.getLogger(Services.class.getName()).log(
309: Level.WARNING, null, ex);
310: }
311: }
312: }
313: }
314:
315: /** test if instance cookie is instance of clazz*/
316: private static boolean instanceOf(InstanceCookie inst, Class clazz) {
317: if (inst instanceof InstanceCookie.Of) {
318: return ((InstanceCookie.Of) inst).instanceOf(clazz);
319: } else {
320: try {
321: return clazz.isAssignableFrom(inst.instanceClass());
322: } catch (Exception ex) {
323: Logger.getLogger(Services.class.getName()).log(
324: Level.WARNING, null, ex);
325: return false;
326: }
327: }
328: }
329:
330: /** all services */
331: public Enumeration<ServiceType> services() {
332: return Collections.enumeration(getServiceTypes());
333: }
334:
335: /** Get all available services that are subclass of given class
336: * @param clazz the class that all services should be subclass of
337: * @return an enumeration of {@link ServiceType}s that are subclasses of
338: * given class
339: */
340: public <T extends ServiceType> Enumeration<T> services(
341: Class<T> clazz) {
342: if (clazz == null)
343: return org.openide.util.Enumerations.empty();
344: Collection res = Lookup.getDefault().lookupAll(clazz);
345: return Collections.enumeration(res);
346: }
347:
348: /** Write the object down.
349: */
350: private void writeObject(ObjectOutputStream oos) throws IOException {
351: Enumeration en = services();
352: while (en.hasMoreElements()) {
353: ServiceType s = (ServiceType) en.nextElement();
354:
355: NbMarshalledObject obj;
356: try {
357: obj = new NbMarshalledObject(s);
358: } catch (IOException ex) {
359: Logger.getLogger(Services.class.getName()).log(
360: Level.WARNING, null, ex);
361: // skip the object if it cannot be serialized
362: obj = null;
363: }
364: if (obj != null) {
365: oos.writeObject(obj);
366: }
367: }
368:
369: oos.writeObject(null);
370: }
371:
372: /** Read the object.
373: */
374: private void readObject(ObjectInputStream oos) throws IOException,
375: ClassNotFoundException {
376: final LinkedList<ServiceType> ll = new LinkedList<ServiceType>();
377: for (;;) {
378: NbMarshalledObject obj = (NbMarshalledObject) oos
379: .readObject();
380:
381: if (obj == null) {
382: break;
383: }
384: try {
385: ServiceType s = (ServiceType) obj.get();
386:
387: ll.add(s);
388: } catch (IOException ex) {
389: Logger.getLogger(Services.class.getName()).log(
390: Level.WARNING, null, ex);
391: } catch (ClassNotFoundException ex) {
392: Logger.getLogger(Services.class.getName()).log(
393: Level.WARNING, null, ex);
394: }
395: }
396:
397: getDefault().setServiceTypes(ll);
398: }
399:
400: /** Only one instance */
401: private Object readResolve() {
402: return getDefault();
403: }
404: }
|