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-2007 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: * QueryUnusedGlobalsReader.java
043: *
044: * Created on April 11, 2006, 4:00 PM
045: *
046: * To change this template, choose Tools | Template Manager
047: * and open the template in the editor.
048: */
049:
050: package org.netbeans.modules.xml.schema.refactoring.query.readers;
051:
052: import java.text.MessageFormat;
053: import java.util.ArrayList;
054: import java.util.Collection;
055: import java.util.Iterator;
056: import java.util.List;
057: import java.util.Map;
058: import org.netbeans.api.project.SourceGroup;
059: import org.netbeans.modules.xml.nbprefuse.AnalysisConstants;
060: import org.netbeans.modules.xml.refactoring.spi.SharedUtils;
061: import org.netbeans.modules.xml.refactoring.spi.UIHelper;
062: import org.netbeans.modules.xml.refactoring.ui.CancelSignal;
063: import org.netbeans.modules.xml.schema.model.GlobalAttribute;
064: import org.netbeans.modules.xml.schema.model.GlobalAttributeGroup;
065: import org.netbeans.modules.xml.schema.model.GlobalComplexType;
066: import org.netbeans.modules.xml.schema.model.GlobalElement;
067: import org.netbeans.modules.xml.schema.model.GlobalGroup;
068: import org.netbeans.modules.xml.schema.model.GlobalSimpleType;
069: import org.netbeans.modules.xml.schema.model.Schema;
070: import org.netbeans.modules.xml.schema.model.SchemaComponent;
071: import org.netbeans.modules.xml.schema.model.SchemaModel;
072: import org.netbeans.modules.xml.schema.model.SchemaModelFactory;
073: import org.netbeans.modules.xml.schema.model.visitor.Preview;
074: import org.netbeans.modules.xml.schema.refactoring.SchemaUIHelper;
075: import org.netbeans.modules.xml.schema.refactoring.ui.QueryUtilities;
076: import org.netbeans.modules.xml.schema.ui.nodes.categorized.CategorizedSchemaNodeFactory;
077: import org.netbeans.modules.xml.xam.Model;
078: import org.netbeans.modules.xml.xam.ModelSource;
079: import org.netbeans.modules.xml.xam.NamedReferenceable;
080: import org.netbeans.modules.xml.xam.Referenceable;
081: import org.openide.awt.StatusDisplayer;
082: import org.openide.filesystems.FileObject;
083: import org.openide.nodes.AbstractNode;
084: import org.openide.nodes.Children;
085: import org.openide.nodes.FilterNode;
086: import org.openide.nodes.Node;
087: import org.openide.util.NbBundle;
088: import org.openide.util.lookup.Lookups;
089:
090: /**
091: *
092: * @author Jeri Lockhart
093: */
094: public class QueryUnusedGlobalsReader {
095:
096: private enum FindUsagesResult {
097: USAGES_FOUND, NO_USAGES_FOUND, CANCEL_REQUESTED
098: };
099:
100: private static final int GCT = 2;
101: private static final int GST = 5;
102: private static final int GRP = 4;
103: private static final int AT = 0;
104: private static final int ATG = 1;
105: private static final int ELE = 3;
106:
107: /**
108: * Return the root node of a tree containing any unused global components
109: * by component type category
110: *
111: */
112: public Node findUnusedGlobals(CancelSignal cancelSignal,
113: SchemaModel model, Boolean excludeGEs) {
114: if (cancelSignal == null || model == null || excludeGEs == null) {
115: return null;
116: }
117:
118: AbstractNode root = new AbstractNode(new Children.Array());
119: root.setDisplayName(NbBundle.getMessage(
120: QueryUnusedGlobalsReader.class,
121: "LBL_Unused_Global_Components"));
122: root
123: .setIconBaseWithExtension("org/netbeans/modules/xml/schema/refactoring/resources/unused-query.PNG");//NOI18N
124: Schema schema = model.getSchema();
125:
126: Node[] catChildren = new Node[excludeGEs.booleanValue() ? 5 : 6];
127:
128: List<SchemaComponent> theGlobals = new ArrayList<SchemaComponent>();
129:
130: Collection<GlobalComplexType> cts = schema.getComplexTypes();
131: Node ctCat = QueryUtilities
132: .createCategoryNode(AnalysisConstants.GlobalTypes.COMPLEX_TYPE);
133: catChildren[GCT] = ctCat;
134: theGlobals.addAll(cts);
135: Collection<GlobalElement> elems = null;
136: int groupExcludedOffset = 1;
137: if (!excludeGEs) {
138: groupExcludedOffset--;
139: elems = schema.getElements();
140: Node eCat = QueryUtilities
141: .createCategoryNode(AnalysisConstants.GlobalTypes.ELEMENT);
142: catChildren[ELE] = eCat;
143: theGlobals.addAll(elems);
144: }
145:
146: Collection<GlobalSimpleType> sts = schema.getSimpleTypes();
147: Node stCat = QueryUtilities
148: .createCategoryNode(AnalysisConstants.GlobalTypes.SIMPLE_TYPE);
149: catChildren[GST - groupExcludedOffset] = stCat;
150: theGlobals.addAll(sts);
151:
152: Collection<GlobalGroup> ggs = schema.getGroups();
153: Node gCat = QueryUtilities
154: .createCategoryNode(AnalysisConstants.GlobalTypes.GROUP);
155: catChildren[GRP - groupExcludedOffset] = gCat;
156: theGlobals.addAll(ggs);
157:
158: Collection<GlobalAttribute> ats = schema.getAttributes();
159: Node atCat = QueryUtilities
160: .createCategoryNode(AnalysisConstants.GlobalTypes.ATTRIBUTE);
161: catChildren[AT] = atCat;
162: theGlobals.addAll(ats);
163:
164: Collection<GlobalAttributeGroup> ags = schema
165: .getAttributeGroups();
166: Node agCat = QueryUtilities
167: .createCategoryNode(AnalysisConstants.GlobalTypes.ATTRIBUTE_GROUP);
168: catChildren[ATG] = agCat;
169: theGlobals.addAll(ags);
170:
171: List<FileObject> allFiles = new ArrayList<FileObject>();
172: FileObject qFile = (FileObject) model.getModelSource()
173: .getLookup().lookup(FileObject.class);
174: // System.out.println("QueryUnusedGlobalsReader file added: " + qFile.getNameExt());
175: allFiles.add(qFile);
176:
177: // then its siblings in the same folder, and the schemas in subfolders
178: FileObject queryFolder = qFile.getParent();
179: getFiles(allFiles, queryFolder, null, qFile);
180:
181: List<SourceGroup> srcGrps = QueryUtilities
182: .getProjectSourceGroups(model,
183: SharedUtils.SOURCES_TYPE_JAVA);
184:
185: if (srcGrps != null) {
186: // lastly, the other files in the project
187: for (SourceGroup srcGrp : srcGrps) {
188: FileObject f = srcGrp.getRootFolder();
189: if (f != queryFolder) {
190: getFiles(allFiles, f, queryFolder, qFile);
191: }
192: }
193: }
194: findUnused(cancelSignal, theGlobals, allFiles);
195: if (cancelSignal.isCancelRequested()) {
196: StatusDisplayer.getDefault().setStatusText(
197: NbBundle.getMessage(QueryUnusedGlobalsReader.class,
198: "LBL_Query_Cancelled"));
199: return null;
200: }
201: for (SchemaComponent sc : theGlobals) {
202: createNode(sc, catChildren, groupExcludedOffset);
203: }
204:
205: root.getChildren().add(catChildren);
206: StatusDisplayer
207: .getDefault()
208: .setStatusText(
209: (theGlobals.size() == 1 ? NbBundle.getMessage(
210: QueryUnusedGlobalsReader.class,
211: "LBL_Found_1_Unused_Component")
212: : MessageFormat
213: .format(
214: NbBundle
215: .getMessage(
216: QueryUnusedGlobalsReader.class,
217: "LBL_Found_Unused_Global_Components"),
218: new Object[] { Integer
219: .valueOf(theGlobals
220: .size()) })));
221:
222: // System.out.println("Global components count: " + theGlobals.size() );
223: // System.out.println("Files searched count: " + allFiles.size() );
224: //
225: // System.out.println("Time to find unused components: " +
226: // ((System.currentTimeMillis()-start)/1000f) + " seconds");//NOI18N
227:
228: return root;
229: }
230:
231: ///////////////////////////////////////////////////////////////////////////
232: // private methods
233: ///////////////////////////////////////////////////////////////////////////
234:
235: private void findUnused(CancelSignal cancelSignal,
236: List<SchemaComponent> theGlobals, List<FileObject> theFiles) {
237: Iterator<FileObject> filesIt = theFiles.iterator();
238: while (filesIt.hasNext()) {
239: FileObject f = filesIt.next();
240: // System.out.println("Scanning "+ f.getNameExt());
241: ModelSource modelSource = org.netbeans.modules.xml.retriever.catalog.Utilities
242: .getModelSource(f, true); // readOnly
243:
244: SchemaModel currModel = SchemaModelFactory.getDefault()
245: .getModel(modelSource);
246: if (currModel.getState() == Model.State.NOT_WELL_FORMED) {
247: continue;
248: }
249: assert currModel != null : "Cannot get SchemaModel for "
250: + f.getNameExt();
251: Iterator<SchemaComponent> scIt = theGlobals.iterator();
252: // System.out.println("Globals remaining " + theGlobals.size());
253: while (scIt.hasNext()) {
254: if (cancelSignal.isCancelRequested()) {
255: return;
256: }
257: SchemaComponent sc = scIt.next();
258: Referenceable ref = Referenceable.class.cast(sc);
259: // CR check if currModel is valid
260: Preview preview = QueryUtilities.getUsagesPreview(
261: currModel.getSchema(), NamedReferenceable.class
262: .cast(ref));
263:
264: assert preview != null : "QueryUtilities.getUsagesPreview() returned null preview";//NOI18N
265: Map<SchemaComponent, List<SchemaComponent>> um = preview
266: .getUsages();
267: assert um != null : "QueryUtilities.getUsagesPreview() returned preview with null map"; //NOI18N
268:
269: if (um.size() > 0) {
270: // System.out.println("Removed " + Named.class.cast(sc).getName());
271: scIt.remove();
272: }
273: // else {
274: // System.out.println("Kept " + Named.class.cast(sc).getName());
275: // }
276: }
277: }
278: }
279:
280: /**
281: * Recursive methods to get all subfolders and files
282: *
283: */
284: private void getFiles(List<FileObject> allFiles, FileObject fobj,
285: FileObject queryFolder, FileObject queryFile) {
286:
287: if (fobj != null && fobj.isFolder() && fobj != queryFolder) {
288: FileObject[] children = fobj.getChildren();
289: for (FileObject f : children) {
290: if (f.isData()
291: && f
292: .getExt()
293: .equals(
294: AnalysisConstants.SCHEMA_FILE_EXTENSION)
295: && f != queryFile) { // it's a schema dataobject
296: // System.out.println("QueryUnusedGlobalsReader file added: " + f.getNameExt());
297: allFiles.add(f);
298: } else { // it's a folder
299: getFiles(allFiles, f, queryFolder, queryFile);
300: }
301: }
302: }
303:
304: }
305:
306: /**
307: * Creates an AbstractNode for the schema component
308: * and adds it to the children of the categoryNode
309: * If the categoryNode is null, creates it and adds it to
310: * the children of the root node
311: *
312: */
313: private void createNode(SchemaComponent sc, Node[] categories,
314: int groupExcludedOffset) {
315: if (!(sc instanceof Referenceable) || categories == null) {
316: return;
317: }
318: int index = 0;
319: if (sc instanceof GlobalComplexType) {
320: index = GCT;
321: } else if (sc instanceof GlobalSimpleType) {
322: index = GST - groupExcludedOffset;
323: } else if (sc instanceof GlobalGroup) {
324: index = GRP - groupExcludedOffset;
325: } else if (sc instanceof GlobalAttribute) {
326: index = AT;
327: } else if (sc instanceof GlobalAttributeGroup) {
328: index = ATG;
329: } else if (sc instanceof GlobalElement) {
330: index = ELE;
331: }
332:
333: //System.out.println("QueryUnusedGlobalsReader:: create node called");
334: SchemaUIHelper uiHelper = new SchemaUIHelper();
335: Node displayNode = uiHelper.getDisplayNode(sc);
336: // Node displayNode = RefactoringManager.getInstance().
337: // getTargetComponentUIHelper((Referenceable)sc).getDisplayNode(sc);
338: displayNode = new FilterNode(displayNode) {
339: public String getHtmlDisplayName() {
340: return null;
341: }
342: };
343: categories[index].getChildren().add(new Node[] { displayNode });
344: }
345: }
|