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.modules.gsfret.source.usages;
043:
044: import java.util.ArrayList;
045: import java.util.Arrays;
046: import java.util.Collections;
047: import java.util.List;
048: import java.util.Set;
049: import org.apache.lucene.document.DateTools;
050: import org.apache.lucene.document.Document;
051: import org.apache.lucene.document.Field;
052: import org.apache.lucene.index.Term;
053: import org.apache.lucene.search.BooleanClause;
054: import org.apache.lucene.search.BooleanQuery;
055: import org.apache.lucene.search.PrefixQuery;
056: import org.apache.lucene.search.Query;
057: import org.apache.lucene.search.TermQuery;
058: import org.apache.lucene.search.WildcardQuery;
059:
060: /**
061: * This file is originally from Retouche, the Java Support
062: * infrastructure in NetBeans. I have modified the file as little
063: * as possible to make merging Retouche fixes back as simple as
064: * possible.
065: *
066: *
067: * @author Tomas Zezula
068: */
069: class DocumentUtil {
070:
071: private static final String ROOT_NAME = "/"; //NOI18N
072: private static final String FIELD_RESOURCE_NAME = "resName"; //NOI18N
073: private static final String FIELD_BINARY_NAME = "binaryName"; //NOI18N
074: private static final String FIELD_PACKAGE_NAME = "packageName"; //NOI18N
075: static final String FIELD_TIME_STAMP = "timeStamp"; //NOI18N
076: static final String FIELD_FILENAME = "filename"; //NOI18N
077: private static final String FIELD_REFERENCES = "references"; //NOI18N
078: private static final String FIELD_SIMPLE_NAME = "simpleName"; //NOI18N
079: private static final String FIELD_CASE_INSENSITIVE_NAME = "ciName"; //NOI18N
080:
081: private static final char NO = '-'; //NOI18N
082: private static final char YES = '+'; //NOI18N
083: private static final char WILDCARD = '?'; //NOI18N
084: private static final char PKG_SEPARATOR = '.'; //NOI18N
085:
086: private static final char EK_CLASS = 'C'; //NOI18N
087: private static final char EK_INTERFACE = 'I'; //NOI18N
088: private static final char EK_ENUM = 'E'; //NOI18N
089: private static final char EK_ANNOTATION = 'A'; //NOI18N
090:
091: private static final int SIZE = ClassIndexImpl.UsageType.values().length;
092: private static final char[] MASK_ANY_USAGE = new char[SIZE];
093:
094: static {
095: Arrays.fill(MASK_ANY_USAGE, WILDCARD); //NOI18N
096: }
097:
098: private DocumentUtil() {
099: }
100:
101: //Document field getters
102: public static String getBinaryName(final Document doc) {
103: /*
104: return getBinaryName(doc, null);
105: }
106:
107: public static String getBinaryName (final Document doc, final ElementKind[] kind) {
108: */
109: assert doc != null;
110: final Field pkgField = doc.getField(FIELD_PACKAGE_NAME);
111: final Field snField = doc.getField(FIELD_BINARY_NAME);
112: if (snField == null) {
113: return null;
114: }
115: final String tmp = snField.stringValue();
116: final String snName = tmp.substring(0, tmp.length() - 1);
117: // if (kind != null) {
118: // assert kind.length == 1;
119: // kind[0] = decodeKind (tmp.charAt(tmp.length()-1));
120: // }
121: if (pkgField == null) {
122: return snName;
123: }
124: return pkgField.stringValue() + PKG_SEPARATOR + snName; //NO I18N
125: }
126:
127: public static String getSimpleBinaryName(final Document doc) {
128: assert doc != null;
129: Field field = doc.getField(FIELD_BINARY_NAME);
130: if (field == null) {
131: return null;
132: } else {
133: return field.stringValue();
134: }
135: }
136:
137: public static String getPackageName(final Document doc) {
138: assert doc != null;
139: Field field = doc.getField(FIELD_PACKAGE_NAME);
140: return field == null ? null : field.stringValue();
141: }
142:
143: static String getRefereneType(final Document doc,
144: final String className) {
145: assert doc != null;
146: assert className != null;
147: Field[] fields = doc.getFields(FIELD_REFERENCES);
148: assert fields != null;
149: for (Field field : fields) {
150: final String rawUsage = field.stringValue();
151: final int rawUsageLen = rawUsage.length();
152: assert rawUsageLen > SIZE;
153: final int index = rawUsageLen - SIZE;
154: final String usageName = rawUsage.substring(0, index);
155: final String map = rawUsage.substring(index);
156: if (className.equals(usageName)) {
157: return map;
158: }
159: }
160: return null;
161: }
162:
163: public static List<String> getReferences(final Document doc) {
164: assert doc != null;
165: Field[] fields = doc.getFields(FIELD_REFERENCES);
166: assert fields != null;
167: List<String> result = new ArrayList<String>(fields.length);
168: for (Field field : fields) {
169: result.add(field.stringValue());
170: }
171: return result;
172: }
173:
174: public static long getTimeStamp(final Document doc)
175: throws java.text.ParseException {
176: assert doc != null;
177: Field field = doc.getField(FIELD_TIME_STAMP);
178: assert field != null;
179: String data = field.stringValue();
180: assert data != null;
181: return DateTools.stringToTime(data);
182: }
183:
184: //Term and query factories
185: public static Query binaryNameQuery(final String resourceName) {
186: BooleanQuery query = new BooleanQuery();
187: int index = resourceName.lastIndexOf(PKG_SEPARATOR); // NOI18N
188: String pkgName, sName;
189: if (index < 0) {
190: pkgName = ""; // NOI18N
191: sName = resourceName;
192: } else {
193: pkgName = resourceName.substring(0, index);
194: sName = resourceName.substring(index + 1);
195: }
196: sName = sName + WILDCARD;
197: query.add(new TermQuery(new Term(FIELD_PACKAGE_NAME, pkgName)),
198: BooleanClause.Occur.MUST);
199: query.add(
200: new WildcardQuery(new Term(FIELD_BINARY_NAME, sName)),
201: BooleanClause.Occur.MUST);
202: return query;
203: }
204:
205: public static Query binaryContentNameQuery(final String resourceName) {
206: int index = resourceName.lastIndexOf(PKG_SEPARATOR); // NOI18N
207: String pkgName, sName;
208: if (index < 0) {
209: pkgName = ""; // NOI18N
210: sName = resourceName;
211: } else {
212: pkgName = resourceName.substring(0, index);
213: sName = resourceName.substring(index + 1);
214: }
215: BooleanQuery query = new BooleanQuery();
216: BooleanQuery subQuery = new BooleanQuery();
217: subQuery.add(new WildcardQuery(new Term(FIELD_BINARY_NAME,
218: sName + WILDCARD)), BooleanClause.Occur.SHOULD);
219: subQuery.add(new PrefixQuery(new Term(FIELD_BINARY_NAME,
220: sName + '$')), BooleanClause.Occur.SHOULD);
221: query.add(new TermQuery(new Term(FIELD_PACKAGE_NAME, pkgName)),
222: BooleanClause.Occur.MUST);
223: query.add(subQuery, BooleanClause.Occur.MUST);
224: return query;
225: }
226:
227: public static Term rootDocumentTerm() {
228: return new Term(FIELD_RESOURCE_NAME, ROOT_NAME);
229: }
230:
231: // public static Term simpleBinaryNameTerm (final String resourceFileName) {
232: // assert resourceFileName != null;
233: // return new Term (FIELD_BINARY_NAME, resourceFileName);
234: // }
235: //
236: // public static Term packageNameTerm (final String packageName) {
237: // assert packageName != null;
238: // return new Term (FIELD_PACKAGE_NAME, packageName);
239: // }
240: //
241: // public static Term referencesTerm (String resourceName, final Set<ClassIndexImpl.UsageType> usageType) {
242: // assert resourceName != null;
243: // if (usageType != null) {
244: // resourceName = encodeUsage (resourceName, usageType, WILDCARD).toString();
245: // }
246: // else {
247: // StringBuilder sb = new StringBuilder (resourceName);
248: // sb.append(MASK_ANY_USAGE);
249: // resourceName = sb.toString();
250: // }
251: // return new Term (FIELD_REFERENCES, resourceName);
252: // }
253: //
254: // public static Term simpleNameTerm (final String resourceSimpleName) {
255: // assert resourceSimpleName != null;
256: // return new Term (FIELD_SIMPLE_NAME, resourceSimpleName);
257: // }
258: //
259: // public static Term caseInsensitiveNameTerm (final String caseInsensitiveName) {
260: // assert caseInsensitiveName != null;
261: // return new Term (FIELD_CASE_INSENSITIVE_NAME, caseInsensitiveName);
262: // }
263:
264: //Factories for lucene document
265: public static Document createDocument(final String binaryName,
266: final long timeStamp, List<String> references) {
267: assert binaryName != null;
268: assert references != null;
269: int index = binaryName.lastIndexOf(PKG_SEPARATOR); //NOI18N
270: String fileName, pkgName, simpleName, caseInsensitiveName;
271: if (index < 0) {
272: fileName = binaryName;
273: pkgName = ""; //NOI18N
274: } else {
275: fileName = binaryName.substring(index + 1);
276: pkgName = binaryName.substring(0, index);
277: }
278: index = fileName.lastIndexOf('$'); //NOI18N
279: if (index < 0) {
280: simpleName = fileName.substring(0, fileName.length() - 1);
281: } else {
282: simpleName = fileName.substring(index + 1, fileName
283: .length() - 1);
284: }
285: caseInsensitiveName = simpleName.toLowerCase(); //XXX: I18N, Locale
286: Document doc = new Document();
287: Field field = new Field(FIELD_BINARY_NAME, fileName,
288: Field.Store.YES, Field.Index.UN_TOKENIZED);
289: doc.add(field);
290: field = new Field(FIELD_PACKAGE_NAME, pkgName, Field.Store.YES,
291: Field.Index.UN_TOKENIZED);
292: doc.add(field);
293: field = new Field(FIELD_TIME_STAMP, DateTools.timeToString(
294: timeStamp, DateTools.Resolution.MILLISECOND),
295: Field.Store.YES, Field.Index.NO);
296: doc.add(field);
297: field = new Field(FIELD_SIMPLE_NAME, simpleName,
298: Field.Store.YES, Field.Index.UN_TOKENIZED);
299: doc.add(field);
300: field = new Field(FIELD_CASE_INSENSITIVE_NAME,
301: caseInsensitiveName, Field.Store.YES,
302: Field.Index.UN_TOKENIZED);
303: doc.add(field);
304: for (String reference : references) {
305: field = new Field(FIELD_REFERENCES, reference,
306: Field.Store.YES, Field.Index.UN_TOKENIZED);
307: doc.add(field);
308: }
309: return doc;
310: }
311:
312: public static Document createRootTimeStampDocument(
313: final long timeStamp) {
314: Document doc = new Document();
315: Field field = new Field(FIELD_RESOURCE_NAME, ROOT_NAME,
316: Field.Store.YES, Field.Index.UN_TOKENIZED);
317: doc.add(field);
318: field = new Field(FIELD_TIME_STAMP, DateTools.timeToString(
319: timeStamp, DateTools.Resolution.MILLISECOND),
320: Field.Store.YES, Field.Index.NO);
321: doc.add(field);
322: return doc;
323: }
324:
325: // Functions for encoding and decoding of UsageType
326: public static StringBuilder createUsage(final String className) {
327: Set<ClassIndexImpl.UsageType> EMPTY = Collections.emptySet();
328: return encodeUsage(className, EMPTY, NO);
329: }
330:
331: public static void addUsage(final StringBuilder rawUsage,
332: final ClassIndexImpl.UsageType type) {
333: assert rawUsage != null;
334: assert type != null;
335: final int rawUsageLen = rawUsage.length();
336: final int startIndex = rawUsageLen - SIZE;
337: rawUsage.setCharAt(startIndex + type.getOffset(), YES);
338: }
339:
340: public static String encodeUsage(final String className,
341: final Set<ClassIndexImpl.UsageType> usageTypes) {
342: return encodeUsage(className, usageTypes, NO).toString();
343: }
344:
345: private static StringBuilder encodeUsage(final String className,
346: final Set<ClassIndexImpl.UsageType> usageTypes, char fill) {
347: assert className != null;
348: assert usageTypes != null;
349: StringBuilder builder = new StringBuilder();
350: builder.append(className);
351: char[] map = new char[SIZE];
352: Arrays.fill(map, fill);
353: for (ClassIndexImpl.UsageType usageType : usageTypes) {
354: int offset = usageType.getOffset();
355: assert offset >= 0 && offset < SIZE;
356: map[offset] = YES;
357: }
358: builder.append(map);
359: return builder;
360: }
361:
362: public static String encodeUsage(final String className,
363: final String usageMap) {
364: assert className != null;
365: assert usageMap != null;
366: StringBuilder sb = new StringBuilder();
367: sb.append(className);
368: sb.append(usageMap);
369: return sb.toString();
370: }
371:
372: public static String decodeUsage(final String rawUsage,
373: final Set<ClassIndexImpl.UsageType> usageTypes) {
374: assert rawUsage != null;
375: assert usageTypes != null;
376: assert usageTypes.isEmpty();
377: final int rawUsageLen = rawUsage.length();
378: assert rawUsageLen > SIZE;
379: final int index = rawUsageLen - SIZE;
380: final String className = rawUsage.substring(0, index);
381: final String map = rawUsage.substring(index);
382: for (ClassIndexImpl.UsageType usageType : ClassIndexImpl.UsageType
383: .values()) {
384: if (map.charAt(usageType.getOffset()) == YES) {
385: usageTypes.add(usageType);
386: }
387: }
388: return className;
389: }
390:
391: // public static ElementKind decodeKind (char kind) {
392: // switch (kind) {
393: // case EK_CLASS:
394: // return ElementKind.CLASS;
395: // case EK_INTERFACE:
396: // return ElementKind.INTERFACE;
397: // case EK_ENUM:
398: // return ElementKind.ENUM;
399: // case EK_ANNOTATION:
400: // return ElementKind.ANNOTATION_TYPE;
401: // default:
402: // throw new IllegalArgumentException ();
403: // }
404: // }
405: //
406: // public static char encodeKind (ElementKind kind) {
407: // switch (kind) {
408: // case CLASS:
409: // return EK_CLASS;
410: // case INTERFACE:
411: // return EK_INTERFACE;
412: // case ENUM:
413: // return EK_ENUM;
414: // case ANNOTATION_TYPE:
415: // return EK_ANNOTATION;
416: // default:
417: // throw new IllegalArgumentException ();
418: // }
419: // }
420:
421: }
|