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: package org.netbeans.modules.vmd.api.model;
042:
043: import org.openide.util.Mutex;
044: import org.openide.util.WeakSet;
045: import org.openide.util.Exceptions;
046:
047: import java.util.*;
048:
049: /**
050: * This class represents a registry for all component descriptors that could be used in the document. The registry consists of
051: * two parts: global registry, project-dependent registry.
052: * <p>
053: * For registering a component descriptor in global registry you have to put its instance to "vmd/components" folder in layer filesystem.
054: * These descriptors will be available for all documents in all projects.
055: * <p>
056: * For registering a component descriptor in project-dependent registry it is fully up-to the project interface what directory
057: * it supply as a source of descriptors (usually it will be nbproject/private/components folder). These component descriptors
058: * will be available only for documents that are located in the project.
059: * <p>
060: * Each component descriptor is registered with the type id that is resolved by
061: * ComponentDescriptor.getTypeDescriptor ().getThisType () method call.
062: * This type id must be unique across all component descriptors. If there is a conflict of type ids,
063: * the one from global registry wins. Otherwise there is no stable rule or priority defined.
064: * <p>
065: * When a registry is update/refreshed/changed all its document (that are using it) resolves a new component descriptors
066: * for all their components. If a component descriptor could not be resolved for some component that the component we still
067: * contain all property values and presenters but they will not be accessible/modifiable.
068: *
069: * @author David Kaspar
070: */
071: // TODO - unique producers by their ids
072: public final class DescriptorRegistry {
073:
074: // TODO - where to store, project-dependent descriptor registry - layer/vmd/projects/project_id/components folder?
075:
076: // private String projectType;
077: // private String projectID;
078:
079: private final Mutex mutex = new Mutex();
080: private final WeakSet<DescriptorRegistryListener> listeners = new WeakSet<DescriptorRegistryListener>();
081: private HashMap<TypeID, ComponentDescriptor> descriptors = new HashMap<TypeID, ComponentDescriptor>();
082: private ArrayList<ComponentProducer> producers = new ArrayList<ComponentProducer>();
083: private GlobalDescriptorRegistry globalDescriptorRegistry;
084: private DescriptorRegistryListener listener = new DescriptorRegistryListener() {
085: public void descriptorRegistryUpdated() {
086: reload();
087: }
088: };
089:
090: /**
091: * Returns a descriptor registry for specific project type and project id
092: * @param projectType the project type
093: * @param projectID the project id
094: * @return the descriptor registry
095: */
096: public static DescriptorRegistry getDescriptorRegistry(
097: String projectType, String projectID) {
098: return GlobalDescriptorRegistry.getGlobalDescriptorRegistry(
099: projectType).getProjectRegistry(projectID);
100: }
101:
102: DescriptorRegistry(GlobalDescriptorRegistry globalDescriptorRegistry) { //, String projectType, String projectID) {
103: assert Debug.isFriend(GlobalDescriptorRegistry.class,
104: "getProjectRegistry"); // NOI18N
105:
106: // this.projectType = projectType;
107: // this.projectID = projectID;
108: this .globalDescriptorRegistry = globalDescriptorRegistry; // GlobalDescriptorRegistry.getGlobalDescriptorRegistry (projectType);
109: globalDescriptorRegistry.addRegistryListener(listener);
110: reload();
111: }
112:
113: private boolean isAccess() {
114: return mutex.isReadAccess() || mutex.isWriteAccess();
115: }
116:
117: /**
118: * Executes a Runnable.run method with read access.
119: * @param runnable the runnable
120: */
121: public void readAccess(final Runnable runnable) {
122: globalDescriptorRegistry.readAccess(new Runnable() {
123: public void run() {
124: mutex.readAccess(runnable);
125: }
126: });
127: }
128:
129: private void writeAccess(final Runnable runnable) {
130: globalDescriptorRegistry.readAccess(new Runnable() {
131: public void run() {
132: mutex.writeAccess(runnable);
133: }
134: });
135: }
136:
137: private void reload() {
138: writeAccess(new Runnable() {
139: public void run() {
140: reloadCore();
141: }
142: });
143: }
144:
145: private void reloadCore() {
146: // TODO - reload from project descriptor registry
147:
148: HashMap<TypeID, ComponentDescriptor> tempDescriptors = new HashMap<TypeID, ComponentDescriptor>();
149: ArrayList<ComponentProducer> tempProducers = new ArrayList<ComponentProducer>();
150:
151: Collection<ComponentDescriptor> _descriptors = globalDescriptorRegistry
152: .getComponentDescriptors();
153: for (ComponentDescriptor descriptor : _descriptors)
154: tempDescriptors.put(descriptor.getTypeDescriptor()
155: .getThisType(), descriptor);
156:
157: tempProducers.addAll(globalDescriptorRegistry
158: .getComponentProducers());
159:
160: this .descriptors = tempDescriptors;
161: this .producers = tempProducers;
162:
163: for (DescriptorRegistryListener _listener : listeners) {
164: try {
165: _listener.descriptorRegistryUpdated();
166: } catch (Exception e) {
167: Exceptions.printStackTrace(e);
168: }
169: }
170: }
171:
172: // /**
173: // * Checks whether all specified component type ids are available in the descriptor registry. If some is missing there,
174: // * it tries to resolve it from the sources.
175: // * @param componentTypes the collection of component type ids that has to be checked
176: // */
177: // public void assertComponentDescriptors (Collection<TypeID> componentTypes) {
178: // writeAccess (new Runnable () {
179: // public void run () {
180: // // TODO
181: // }
182: // });
183: // }
184:
185: /**
186: * Returns a component descriptor for a specified type id.
187: * @param componentType the component type id
188: * @return the component descriptor
189: */
190: public ComponentDescriptor getComponentDescriptor(
191: TypeID componentType) {
192: assert isAccess();
193: if (componentType == null)
194: return null;
195: return descriptors.get(componentType);
196: }
197:
198: public void removeComponentDescriptor(final TypeID componentType) {
199: if (componentType != null)
200: globalDescriptorRegistry
201: .writeAccess(new RemoveComponentDescriptorTask(
202: componentType));
203: }
204:
205: // TODO - proxy for GlobalDescriptorRegistry and ProjectRegistry
206: // HINT - always up-to-date when any method is called (synchronize/refresh before working)
207:
208: /**
209: * Returns a collection of all registered component descriptors.
210: * @return the collection of all registered component descriptors
211: */
212: public Collection<ComponentDescriptor> getComponentDescriptors() {
213: assert isAccess();
214: return Collections.unmodifiableCollection(descriptors.values());
215: }
216:
217: /**
218: * Returns a list of all registered component producers.
219: * @return the list of all registered component producers
220: */
221: public List<ComponentProducer> getComponentProducers() {
222: assert isAccess();
223: return Collections.unmodifiableList(producers);
224: }
225:
226: /**
227: * Adds a registry listener.
228: * The DescriptorRegistryListener.descriptorRegistryUpdated method is called everytime the content of registry is changed.
229: * @param listener the listener
230: */
231: public void addRegistryListener(
232: final DescriptorRegistryListener listener) {
233: writeAccess(new Runnable() {
234: public void run() {
235: listeners.add(listener);
236: listener.descriptorRegistryUpdated();
237: }
238: });
239: }
240:
241: /**
242: * Removes a registry listener.
243: * @param listener the listener
244: */
245: public void removeRegistryListener(
246: final DescriptorRegistryListener listener) {
247: writeAccess(new Runnable() {
248: public void run() {
249: listeners.remove(listener);
250: }
251: });
252: }
253:
254: /**
255: * Checks whether a component descriptor is compatible (descriptor analogy of instanceof operator) with a type id.
256: * Means: Specified component descriptor or its super descriptor has the same type id as the specified one.
257: * @param typeID the type id
258: * @param componentDescriptor the component descriptor
259: * @return true if compatible
260: */
261: private boolean isComponentDescriptorCompatibleWithTypeID(
262: TypeID typeID, ComponentDescriptor componentDescriptor) {
263: assert isAccess();
264: if (typeID == null)
265: return false;
266: for (;;) {
267: if (componentDescriptor == null)
268: return false;
269: TypeDescriptor typeDescriptor = componentDescriptor
270: .getTypeDescriptor();
271: TypeID checked = typeDescriptor.getThisType();
272: if (checked == null)
273: return false;
274: if (checked.equals(typeID))
275: return true;
276: componentDescriptor = getComponentDescriptor(typeDescriptor
277: .getSuperType());
278: }
279: }
280:
281: /**
282: * Checks whether specified superTypeID is super type id of specified derivedTypeID
283: * @param superTypeID the super type id
284: * @param derivedTypeID the possible derived typeid
285: * @return true if the superTypeID is one of super type ids of the derivedTypeID
286: */
287: public boolean isInHierarchy(TypeID super TypeID,
288: TypeID derivedTypeID) {
289: return isComponentDescriptorCompatibleWithTypeID(super TypeID,
290: getComponentDescriptor(derivedTypeID));
291: }
292:
293: final class RemoveComponentDescriptorTask implements Runnable {
294:
295: private TypeID componentType;
296:
297: public RemoveComponentDescriptorTask(TypeID componentType) {
298: this .componentType = componentType;
299: }
300:
301: public void run() {
302: globalDescriptorRegistry
303: .removeComponentDescriptor(componentType);
304: }
305:
306: }
307:
308: }
|