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.midp.palette.wizard;
042:
043: import org.netbeans.api.java.source.*;
044: import org.netbeans.api.project.Project;
045: import org.netbeans.api.project.SourceGroup;
046: import org.netbeans.modules.vmd.api.io.ProjectUtils;
047: import org.netbeans.modules.vmd.api.model.*;
048: import org.netbeans.modules.vmd.midp.components.MidpDocumentSupport;
049: import org.netbeans.modules.vmd.midp.components.MidpProjectSupport;
050: import org.netbeans.modules.vmd.midp.components.MidpTypes;
051: import org.netbeans.modules.vmd.midp.components.general.ClassCD;
052: import org.netbeans.modules.vmd.midp.palette.MidpPaletteProvider;
053: import org.netbeans.modules.vmd.midp.serialization.MidpPropertyPresenterSerializer;
054: import org.netbeans.modules.vmd.midp.serialization.MidpSetterPresenterSerializer;
055: import org.netbeans.modules.vmd.midp.serialization.MidpTypesConvertor;
056: import org.netbeans.modules.vmd.midp.serialization.MidpAddImportPresenterSerializer;
057: import org.openide.ErrorManager;
058: import org.openide.util.NbBundle;
059: import org.openide.filesystems.FileObject;
060: import org.openide.filesystems.FileUtil;
061:
062: import javax.lang.model.element.*;
063: import javax.lang.model.type.DeclaredType;
064: import javax.lang.model.type.TypeKind;
065: import javax.lang.model.type.TypeMirror;
066: import java.io.IOException;
067: import java.util.*;
068:
069: /**
070: * @author David Kaspar
071: */
072: public final class ComponentInstaller {
073:
074: public static void install(
075: final Map<String, Item> allFoundComponents,
076: final List<Item> componentsToInstall) {
077: ComponentSerializationSupport
078: .runUnderDescriptorRegistryWriteAccess(
079: MidpDocumentSupport.PROJECT_TYPE_MIDP,
080: new Runnable() {
081: public void run() {
082: installCore(allFoundComponents,
083: componentsToInstall);
084: }
085: });
086: ComponentSerializationSupport
087: .refreshDescriptorRegistry(MidpDocumentSupport.PROJECT_TYPE_MIDP);
088: }
089:
090: private static void installCore(
091: Map<String, Item> allFoundComponents,
092: List<Item> componentsToInstall) {
093: HashMap<String, Item> toInstall = new HashMap<String, Item>();
094: for (Item item : componentsToInstall)
095: recursiveAdd(toInstall, allFoundComponents, item);
096: for (Item item : toInstall.values())
097: ComponentSerializationSupport.serialize(
098: MidpDocumentSupport.PROJECT_TYPE_MIDP, item
099: .getTypeDescriptor(), item
100: .getPaletteDescriptor(), item
101: .getProperties(), item.getPresenters());
102: }
103:
104: private static void recursiveAdd(HashMap<String, Item> toInstall,
105: Map<String, Item> allFoundComponents, Item item) {
106: if (item == null)
107: return;
108: if (toInstall.containsKey(item.getFQN()))
109: return;
110: toInstall.put(item.getFQN(), item);
111: recursiveAdd(toInstall, allFoundComponents, allFoundComponents
112: .get(item.getSuperFQN()));
113: }
114:
115: public static Map<String, Item> search(final Project project) {
116: final Object[] ret = new Object[1];
117: ComponentSerializationSupport
118: .runUnderDescriptorRegistryReadAccess(
119: MidpDocumentSupport.PROJECT_TYPE_MIDP,
120: new Runnable() {
121: public void run() {
122: ret[0] = searchCore(project);
123: }
124: });
125: return (Map<String, Item>) ret[0];
126: }
127:
128: public static Map<String, Item> searchCore(Project project) {
129: final ClasspathInfo info = MidpProjectSupport
130: .getClasspathInfo(project);
131: if (info == null)
132: return Collections.emptyMap();
133: final SourceGroup sourceGroup = MidpProjectSupport
134: .getSourceGroup(project);
135: final Set<ElementHandle<TypeElement>> allHandles = info
136: .getClassIndex().getDeclaredTypes(
137: "",
138: ClassIndex.NameKind.PREFIX,
139: EnumSet.of(ClassIndex.SearchScope.SOURCE,
140: ClassIndex.SearchScope.DEPENDENCIES)); // NOI18N
141: final Map<String, ComponentDescriptor> registry = resolveRegistryMap(project);
142: final HashMap<String, Item> result = new HashMap<String, Item>();
143:
144: try {
145: JavaSource.create(info).runUserActionTask(
146: new Task<CompilationController>() {
147:
148: public void run(CompilationController parameter)
149: throws Exception {
150: HashSet<TypeElement> elements = new HashSet<TypeElement>();
151: for (ElementHandle<TypeElement> handle : allHandles) {
152: TypeElement element = handle
153: .resolve(parameter);
154: if (element != null
155: && element.getKind() == ElementKind.CLASS)
156: elements.add(element);
157: }
158:
159: for (;;) {
160: Iterator<TypeElement> iterator = elements
161: .iterator();
162: if (!iterator.hasNext())
163: break;
164: TypeElement element = iterator.next();
165: search(element, elements, registry,
166: info, sourceGroup, result);
167: }
168: }
169: }, true);
170: } catch (IOException e) {
171: ErrorManager.getDefault().notify(e);
172: }
173: return result;
174: }
175:
176: private static Map<String, ComponentDescriptor> resolveRegistryMap(
177: Project project) {
178: final DescriptorRegistry registry = DescriptorRegistry
179: .getDescriptorRegistry(
180: MidpDocumentSupport.PROJECT_TYPE_MIDP,
181: ProjectUtils.getProjectID(project));
182: final HashMap<String, ComponentDescriptor> registryMap = new HashMap<String, ComponentDescriptor>();
183:
184: registry.readAccess(new Runnable() {
185: public void run() {
186: for (ComponentDescriptor descriptor : registry
187: .getComponentDescriptors()) {
188: TypeID this Type = descriptor.getTypeDescriptor()
189: .getThisType();
190:
191: String string = this Type.getString();
192: if (!checkForJavaIdentifierCompliant(string))
193: continue;
194:
195: if (!registry.isInHierarchy(ClassCD.TYPEID,
196: this Type)
197: || ClassCD.TYPEID.equals(this Type))
198: continue;
199:
200: registryMap.put(string, descriptor);
201: }
202: }
203: });
204:
205: return registryMap;
206: }
207:
208: private static boolean search(TypeElement element,
209: Set<TypeElement> elements,
210: Map<String, ComponentDescriptor> registry,
211: ClasspathInfo info, SourceGroup sourceGroup,
212: Map<String, Item> result) {
213: if (element == null)
214: return false;
215:
216: elements.remove(element);
217:
218: if (element.getKind() != ElementKind.CLASS)
219: return false;
220:
221: Name tempQualifiedName = element.getQualifiedName();
222: if (tempQualifiedName == null)
223: return false;
224: String fqn = tempQualifiedName.toString();
225:
226: ComponentDescriptor descriptor = registry.get(fqn);
227: if (descriptor != null)
228: return true;
229: Item item = result.get(fqn);
230: if (item != null)
231: return true;
232:
233: TypeElement super Element = getSuperElement(element);
234: if (super Element == null)
235: return false;
236: if (!search(super Element, elements, registry, info,
237: sourceGroup, result))
238: return false;
239:
240: String super FQN = super Element.getQualifiedName().toString();
241: if (!registry.containsKey(super FQN)
242: && !result.containsKey(super FQN))
243: return false;
244:
245: boolean isAbstract = element.getModifiers().contains(
246: Modifier.ABSTRACT);
247: boolean isFinal = element.getModifiers().contains(
248: Modifier.FINAL);
249: FileObject file = SourceUtils.getFile(ElementHandle
250: .create(element), info);
251: boolean isInSource = file != null
252: && sourceGroup != null
253: && FileUtil.isParentOf(sourceGroup.getRootFolder(),
254: file);
255: item = new Item(super FQN, fqn, isAbstract, isFinal, isInSource);
256: item.addPresenter(new MidpAddImportPresenterSerializer());
257:
258: inspectElement(item, element);
259: // boolean hasConstructor = inspectElement (item, element);
260: // if (! isAbstract && ! hasConstructor)
261: // return false;
262:
263: result.put(fqn, item);
264: return true;
265: }
266:
267: private static boolean inspectElement(Item item, TypeElement clazz) {
268: String fqn = clazz.getQualifiedName().toString();
269: boolean hasConstructor = false;
270: int constructorIndex = 1;
271:
272: for (Element el : clazz.getEnclosedElements()) {
273: if (!el.getModifiers().contains(Modifier.PUBLIC))
274: continue;
275:
276: if (el.getKind() == ElementKind.CONSTRUCTOR) {
277: ExecutableElement method = (ExecutableElement) el;
278: ArrayList<String> properties = new ArrayList<String>();
279: int index = 1;
280: for (VariableElement parameter : method.getParameters()) {
281: PropertyDescriptor property = MidpTypesConvertor
282: .createPropertyDescriptorForParameter(fqn
283: + "#" + constructorIndex + "#"
284: + index, true, parameter); // NOI18N
285: item.addProperty(property);
286: properties.add(property.getName());
287: String displayName = NbBundle.getMessage(
288: ComponentInstaller.class,
289: "NAME_ConstructorParam", new Object[] {
290: parameter.getSimpleName(),
291: constructorIndex, index, fqn }); // NOI18N
292: item
293: .addPresenter(new MidpPropertyPresenterSerializer(
294: displayName, property));
295: index++;
296: }
297: item.addPresenter(new MidpSetterPresenterSerializer(
298: null, properties));
299:
300: } else if (el.getKind() == ElementKind.METHOD) {
301: ExecutableElement method = (ExecutableElement) el;
302: String name = method.getSimpleName().toString();
303: if (!name.startsWith("set") || name.length() < 4
304: || !Character.isUpperCase(name.charAt(3))) // NOI18N
305: continue;
306: ArrayList<String> properties = new ArrayList<String>();
307: List<? extends VariableElement> parameters = method
308: .getParameters();
309: if (parameters.size() != 1)
310: continue;
311: VariableElement parameter = parameters.iterator()
312: .next();
313:
314: PropertyDescriptor property = MidpTypesConvertor
315: .createPropertyDescriptorForParameter(fqn + "#"
316: + name, false, parameter); // NOI18N
317: item.addProperty(property);
318: properties.add(property.getName());
319: String displayName = NbBundle.getMessage(
320: ComponentInstaller.class, "NAME_SetterParam",
321: parameter.getSimpleName(), name, fqn); // NOI18N
322: item.addPresenter(new MidpPropertyPresenterSerializer(
323: displayName, property));
324:
325: item.addPresenter(new MidpSetterPresenterSerializer(
326: name, properties));
327: }
328: }
329:
330: return hasConstructor;
331: }
332:
333: private static TypeElement getSuperElement(TypeElement element) {
334: TypeMirror super Type = element.getSuperclass();
335: if (super Type.getKind() != TypeKind.DECLARED)
336: return null;
337: return (TypeElement) ((DeclaredType) super Type).asElement();
338: }
339:
340: private static boolean checkForJavaIdentifierCompliant(String fqn) {
341: if (fqn == null || fqn.length() < 1)
342: return false;
343: if (!Character.isJavaIdentifierStart(fqn.charAt(0)))
344: return false;
345: boolean dot = false;
346: for (int index = 1; index < fqn.length(); index++) {
347: char c = fqn.charAt(index);
348: if (Character.isJavaIdentifierPart(c)) {
349: dot = false;
350: continue;
351: }
352: if (c != '.')
353: return false;
354: if (dot)
355: return false;
356: dot = true;
357: }
358: return !dot;
359: }
360:
361: public static class Item {
362:
363: private TypeDescriptor typeDescriptor;
364: private PaletteDescriptor paletteDescriptor;
365: private String super FQN;
366: private String fqn;
367: private boolean inSource;
368: private ArrayList<PropertyDescriptor> properties = new ArrayList<PropertyDescriptor>();
369: private ArrayList<PresenterSerializer> presenters = new ArrayList<PresenterSerializer>();
370:
371: public Item(String super FQN, String fqn, boolean isAbstract,
372: boolean isFinal, boolean inSource) {
373: this .super FQN = super FQN;
374: this .fqn = fqn;
375: this .inSource = inSource;
376: TypeID typeID = new TypeID(TypeID.Kind.COMPONENT, fqn);
377: typeDescriptor = new TypeDescriptor(new TypeID(
378: TypeID.Kind.COMPONENT, super FQN), typeID,
379: !isAbstract, !isFinal);
380: paletteDescriptor = new PaletteDescriptor(
381: MidpPaletteProvider.CATEGORY_CUSTOM,
382: MidpTypes.getSimpleClassName(typeID),
383: fqn,
384: "org/netbeans/modules/vmd/midp/resources/components/custom_component_16.png",
385: "org/netbeans/modules/vmd/midp/resources/components/custom_component_32.png"); // NOI18N
386: }
387:
388: public String getSuperFQN() {
389: return super FQN;
390: }
391:
392: public String getFQN() {
393: return fqn;
394: }
395:
396: public boolean isInSource() {
397: return inSource;
398: }
399:
400: public TypeDescriptor getTypeDescriptor() {
401: return typeDescriptor;
402: }
403:
404: public PaletteDescriptor getPaletteDescriptor() {
405: return paletteDescriptor;
406: }
407:
408: public List<PropertyDescriptor> getProperties() {
409: return properties;
410: }
411:
412: public List<PresenterSerializer> getPresenters() {
413: return presenters;
414: }
415:
416: public void addPresenter(PresenterSerializer serializer) {
417: presenters.add(serializer);
418: }
419:
420: public void addProperty(PropertyDescriptor property) {
421: properties.add(property);
422: }
423:
424: }
425:
426: }
|