summaryrefslogtreecommitdiffstats
path: root/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src')
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentMap.java60
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentProcessor.java64
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentProcessorsMap.java106
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DomainSearch.java108
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/IndexException.java45
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/Result.java121
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/ResultFactory.java51
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/ResultProcessor.java50
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ArtifactDocumentProcessor.java107
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/BindingDocumentProcessor.java82
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ComponentDocumentProcessor.java200
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ComponentTypeDocumentProcessor.java186
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/CompositeDocumentProcessor.java128
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ContributionDocumentProcessor.java154
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DefaultFileContent.java57
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DefaultFileDocumentProcessor.java87
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/Document.java113
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainPathAnalyzer.java233
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchAnalyzer.java36
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchDocumentProcessorsMap.java50
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchFileDocumentProcessor.java35
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchFormatter.java68
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchImpl.java371
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchResultFactory.java40
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchResultProcessor.java40
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileContent.java40
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileContentResultProcessor.java105
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileDocumentProcessor.java108
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/HighlightingUtil.java189
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/NamingAnalyzer.java48
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/NamingTokenizer.java149
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ParentField.java206
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/PriorityFieldListResultFactory.java58
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/PropertyDocumentProcessor.java88
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ResultImpl.java270
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ResultProcessorList.java186
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/SearchFields.java73
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/SystemFileContent.java76
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/WrappedFileContent.java73
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ZipDocumentProcessor.java103
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ZipFileContent.java321
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/test/java/org/apache/tuscany/sca/domain/search/impl/DomainPathAnalyzerTestCase.java60
-rw-r--r--sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/test/java/org/apache/tuscany/sca/domain/search/impl/NamingTokenizerTestCase.java158
43 files changed, 4903 insertions, 0 deletions
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentMap.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentMap.java
new file mode 100644
index 0000000000..47deb41a6f
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentMap.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search;
+
+import java.util.HashMap;
+
+import org.apache.tuscany.sca.domain.search.impl.Document;
+
+/**
+ * A map that holds a collection of {@link Document}s. Each {@link Document} key
+ * should ideally be something that is unique across the entire contribution
+ * documents. This class overrides {@link HashMap#get(Object)} method, so it
+ * adds an empty {@link Document} object if the specified key is not found in
+ * the map.
+ *
+ * @version $Rev$ $Date$
+ */
+public class DocumentMap extends HashMap<Object, Document> {
+
+ private static final long serialVersionUID = -2402910290314939928L;
+
+ /**
+ * Returns a {@link Document} object mapped from the specified key. If no
+ * {@link Document} object is found from the specified key, a empty
+ * {@link Document} object is created and added to the map.
+ *
+ * @param key the {@link Document} key
+ * @return the {@link Document} object mapped from the key
+ */
+ @Override
+ public Document get(Object key) {
+ Document doc = super.get(key);
+
+ if (doc == null) {
+ doc = new Document();
+ put(key, doc);
+
+ }
+
+ return doc;
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentProcessor.java
new file mode 100644
index 0000000000..0f183e8875
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentProcessor.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search;
+
+import org.apache.tuscany.sca.domain.search.impl.Document;
+
+/**
+ * A {@link DocumentProcessor} implementations knows how to extract data from a
+ * contribution {@link Object}. The extract data is added to a {@link Document},
+ * which is stored in a {@link DocumentMap}.
+ *
+ * @version $Rev$ $Date$
+ */
+public interface DocumentProcessor {
+
+ final public static Document FAKE_DOCUMENT = new Document();
+
+ /**
+ * Process a contribution {@link Object}, extracting from it data that
+ * should be indexed. The data should be add to a {@link Document} object,
+ * which can be found accessing the {@link DocumentMap} if it's not passed
+ * as an argument. The key used to find the {@link Document} object should
+ * be the one returned by {@link #getDocumentKey(Object)} method.
+ *
+ * @param parentProcessor the processor that invoked this processor, if any
+ * @param documents the {@link DocumentMap} object
+ * @param object the object where data should be extracted from
+ * @param document the {@link Document} object to store the extracted data
+ * @param parent string that represent the object's parent path in the
+ * contribution
+ * @return the resulted {@link Document} object
+ */
+ Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document document,
+ String parent);
+
+ /**
+ * Returns a object key generated from object passed as argument. The key
+ * should be unique in a contribution.
+ *
+ * @param object the object
+ * @return a key generated from the object
+ */
+ Object getDocumentKey(Object object);
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentProcessorsMap.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentProcessorsMap.java
new file mode 100644
index 0000000000..3f8ae0026b
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DocumentProcessorsMap.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search;
+
+import java.util.HashMap;
+
+import org.apache.tuscany.sca.domain.search.impl.Document;
+
+/**
+ * This class is a {@link DocumentProcessor} that holds a map from {@link Class}
+ * -> {@link DocumentProcessor}, and based on this map this processor delegates
+ * the object to be processed to its respective {@link DocumentProcessor}.
+ *
+ * @version $Rev$ $Date$
+ */
+public class DocumentProcessorsMap extends HashMap<Class<?>, DocumentProcessor> implements DocumentProcessor {
+
+ private static final long serialVersionUID = 3967390896890947159L;
+
+ private DocumentProcessor findDocumentProcessor(Object object, Class<?> clazz) {
+ DocumentProcessor processor = get(clazz);
+
+ if (processor == null) {
+ Class<?>[] interfaces = clazz.getInterfaces();
+
+ for (Class<?> interfac : interfaces) {
+ processor = findDocumentProcessor(object, interfac);
+
+ if (processor != null) {
+ return processor;
+ }
+
+ }
+
+ if (!clazz.isInterface()) {
+ return findDocumentProcessor(object, clazz.getSuperclass());
+ }
+
+ }
+
+ return processor;
+
+ }
+
+ /**
+ * @see DocumentProcessor#getDocumentKey(Object)
+ */
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document document,
+ String parent) {
+
+ DocumentProcessor processor = findDocumentProcessor(object, object.getClass());
+
+ if (processor == null) {
+ throw new IllegalArgumentException();
+ }
+
+ if (document == null) {
+ document = documents.get(processor.getDocumentKey(object));
+
+ if (document == null) {
+ document = FAKE_DOCUMENT;
+ }
+
+ }
+
+ processor.process(parentProcessor, documents, object, document, parent);
+
+ return document;
+
+ }
+
+ /**
+ * @see DocumentProcessor#getDocumentKey(Object)
+ */
+ public Object getDocumentKey(Object object) {
+ DocumentProcessor processor = findDocumentProcessor(object, object.getClass());
+
+ if (processor != null) {
+ return processor.getDocumentKey(object);
+
+ } else {
+ return null;
+ }
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DomainSearch.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DomainSearch.java
new file mode 100644
index 0000000000..be7f603b0b
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/DomainSearch.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.search.Query;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.osoa.sca.annotations.Remotable;
+
+/**
+ * This is the interface that must be implemented by the service that provides
+ * the functionality index/search and search contribution data.
+ *
+ * @version $Rev$ $Date$
+ */
+@Remotable
+public interface DomainSearch {
+
+ /**
+ * Returns <code>true</code> if the index is somehow created already, otherwise <code>false</code>.
+ *
+ * @return <code>true</code> if the index is somehow created already, otherwise <code>false</code>
+ */
+ boolean indexExists();
+
+ /**
+ * Parse a query string, execute it against the index and return the results.
+ *
+ * @param searchQuery the string containing the search query
+ * @param highlight <code>true</code> if the results should be highlighted
+ *
+ * @return an array containing the search results
+ *
+ * @throws CorruptIndexException
+ * @throws IOException
+ * @throws ParseException
+ */
+ Result[] parseAndSearch(String searchQuery, boolean highlight) throws IndexException, ParseException;
+
+ /**
+ * Executes a search query against the index and return the results.
+ *
+ * @param searchQuery the search query
+ * @param hightlight highlight <code>true</code> if the results should be highlighted
+ *
+ * @return an array containing the search results
+ *
+ * @throws CorruptIndexException
+ * @throws IOException
+ */
+ Result[] search(Query searchQuery, boolean hightlight) throws IndexException;
+
+ /**
+ * Highlights in the specified text strings that matches the specified search query. The matches can be filtered by field.
+ *
+ * @param field the field to filter
+ * @param text the text to be highlighted
+ * @param searchQuery the search query
+ *
+ * @return the text highlighted
+ *
+ * @throws ParseException
+ * @throws IOException
+ */
+ String highlight(String field, String text, String searchQuery) throws ParseException;
+
+ /**
+ * Adds a contribution to the index.
+ *
+ * @param contribution the contribution to be added
+ */
+ void addContribution(Contribution contribution) throws IndexException;
+
+ /**
+ * Removes a contribution from the index.
+ *
+ * @param contribution the contribution to be removed
+ */
+ void removeContribution(Contribution contribution) throws IndexException;
+
+ /**
+ * Updates a contribution in the index.
+ *
+ * @param oldContribution the old contribution state
+ * @param contribution the new contribution state
+ */
+ void updateContribution(Contribution oldContribution, Contribution contribution) throws IndexException;
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/IndexException.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/IndexException.java
new file mode 100644
index 0000000000..6c74c86387
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/IndexException.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.domain.search;
+
+/**
+ * Exception thrown when a exception occurs while accessing the index.
+ *
+ * @version $Rev$ $Date$
+ */
+public class IndexException extends Exception {
+
+ private static final long serialVersionUID = -6395734136706805723L;
+
+ /**
+ * @see Exception#Exception(String)
+ */
+ public IndexException(String message) {
+ super(message);
+ }
+
+ /**
+ * @see Exception#Exception(String,Throwable)
+ */
+ public IndexException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/Result.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/Result.java
new file mode 100644
index 0000000000..edbebac6b4
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/Result.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * <p>
+ * The object that implements this interface carries a search's result data.
+ * </p>
+ * <p>
+ * A result contains a value, which is the value displayed to the user. It also
+ * contains a field name, which is the field the value is related to.
+ * </p>
+ * <p>
+ * A search result may be split into different {@link Result} objects, each one
+ * contained inside other, representing a complex result hierarchy. For example:
+ * a result structure may represent as result a folder and files/folders
+ * contained in it.
+ * </p>
+ *
+ * @see ResultProcessor
+ * @see ResultFactory
+ *
+ * @version $Rev$ $Date$
+ */
+public interface Result extends Serializable {
+
+ /**
+ * Returns the value held by this object.
+ *
+ * @return the value held by this object
+ */
+ String getValue();
+
+ /**
+ * Sets the result value.
+ *
+ * @param value the result value
+ */
+ void setValue(String value);
+
+ /**
+ * Returns the {@link Result} object that contains this object or
+ * <code>null</code> if it's not contained in any object.
+ *
+ * @return the {@link Result} object that contains this object or
+ * <code>null</code> if it's not contained in any object
+ */
+ Result getContainer();
+
+ /**
+ * A {@link Map} containing {@link Result} objects contained in this
+ * {@link Object}. The contents are mapped from a key, which may be any kind
+ * of identifier, the identifier is chosen by the {@link Result}
+ * implementation.
+ *
+ * @return the contents map
+ */
+ Map<String, Result> getContents();
+
+ /**
+ * Adds a {@link Result} content to this result.
+ *
+ * @param artifactResult the {@link Result} content
+ * @throw {@link UnsupportedOperationException} if the {@link Result}
+ * implementations does not support this operation
+ * @see #getContents()
+ */
+ void addContent(Result artifactResult);
+
+ /**
+ * Removes a {@link Result} content from this result.
+ *
+ * @param artifactResult the {@link Result} content
+ * @throw {@link UnsupportedOperationException} if the {@link Result}
+ * implementations does not support this operation
+ * @see #getContents()
+ */
+ void removeContent(Result artifactResult);
+
+ /**
+ * Sets this object's container.
+ *
+ * @param container the object's container
+ * @see #getContainer()
+ */
+ void setContainer(Result container);
+
+ /**
+ * Returns the field related to the result's value.
+ *
+ * @return the field name
+ */
+ String getField();
+
+ /**
+ * Sets the field related to the result's value.
+ *
+ * @param field the field name
+ */
+ void setField(String field);
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/ResultFactory.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/ResultFactory.java
new file mode 100644
index 0000000000..7a4fb1f5f4
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/ResultFactory.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search;
+
+import org.apache.lucene.document.Document;
+
+/**
+ * This interface should be implemented to provide a way to create
+ * {@link Result} objects from a field name and its value or a {@link Document}
+ * resulted from a search.
+ *
+ * @see Result
+ * @version $Rev$ $Date$
+ */
+public interface ResultFactory<T extends Result> {
+
+ /**
+ * Creates a {@link Result} instance from a field name and its value.
+ *
+ * @param field the field name
+ * @param value the value
+ * @return the {@link Result} instance
+ */
+ T createResult(String field, String value);
+
+ /**
+ * Creates a {@link Result} instance from a {@link Document} object resulted
+ * from a search.
+ *
+ * @param document the result {@link Document}
+ * @return the {@link Result} instance
+ */
+ T createResult(Document document);
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/ResultProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/ResultProcessor.java
new file mode 100644
index 0000000000..8dee35623e
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/ResultProcessor.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search;
+
+import org.apache.lucene.document.Document;
+
+/**
+ * This interface should be implemented by classes that process a
+ * {@link Document} object resulted from a search and create a {@link Result}
+ * object from it.
+ *
+ * @version $Rev$ $Date$
+ */
+public interface ResultProcessor {
+
+ /**
+ * <p>
+ * Process the {@link Document} object and returns a {@link Result} object
+ * containing the processed data.
+ * </p>
+ * <p>
+ * A {@link Result} object may be specified to hold the processed data. If
+ * no object is specified, the implementation must create a new object a
+ * return it.
+ * </p>
+ *
+ * @param document the {@link Document} object resulted from a search
+ * @param result the {@link Result} object that will hold the processed data
+ * or <code>null</code> a new object should be returned.
+ * @return a {@link Result} object containing the processed data
+ */
+ Result process(Document document, Result result);
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ArtifactDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ArtifactDocumentProcessor.java
new file mode 100644
index 0000000000..fcfce34d88
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ArtifactDocumentProcessor.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.lucene.document.Field;
+import org.apache.tuscany.sca.contribution.Artifact;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DocumentProcessor;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ArtifactDocumentProcessor implements DocumentProcessor {
+
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document document,
+ String parent) {
+
+ if (object instanceof Artifact) {
+ Artifact artifact = (Artifact)object;
+
+ if (!(object instanceof Contribution)) {
+
+ String location = artifact.getLocation();
+
+ try {
+
+ if (document == null) {
+ document = documents.get(SearchFields.ARTIFACT_FIELD + location);
+ }
+
+ FileContent fileContent = new WrappedFileContent(new URL(location));
+
+ document.add(new Field(SearchFields.ARTIFACT_FIELD, fileContent.getName(), Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ parent +=
+ DomainPathAnalyzer.PATH_SEPARATOR + SearchFields.ARTIFACT_FIELD
+ + DomainPathAnalyzer.TYPE_SEPARATOR
+ + location
+ + DomainPathAnalyzer.URI_SEPARATOR
+ + fileContent.getName();
+
+ // parent += DomainPathAnalyzer.PATH_SEPARATOR
+ // + SearchFields.FILE_FIELD
+ // + DomainPathAnalyzer.TYPE_SEPARATOR + location +
+ // DomainPathAnalyzer.URI_SEPARATOR + fileContent.getName();
+
+ Document fileDoc = parentProcessor.process(parentProcessor, documents, fileContent, null, parent);
+
+ fileDoc.add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES, Field.Index.ANALYZED));
+
+ } catch (IOException e) {
+ // ignore location
+ }
+
+ }
+
+ return document == null ? FAKE_DOCUMENT : document;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+ public Object getDocumentKey(Object obj) {
+
+ if (obj instanceof Artifact) {
+ Artifact artifact = (Artifact)obj;
+ String uri = artifact.getLocation();
+
+ if (uri != null && uri.length() == 0) {
+ return null;
+ }
+
+ return SearchFields.ARTIFACT_FIELD + uri;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/BindingDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/BindingDocumentProcessor.java
new file mode 100644
index 0000000000..6ae0ff3d57
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/BindingDocumentProcessor.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import org.apache.lucene.document.Field;
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DocumentProcessor;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class BindingDocumentProcessor implements DocumentProcessor {
+
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document document,
+ String parent) {
+
+ if (object instanceof Binding) {
+ Binding binding = (Binding)object;
+ String uri = binding.getURI();
+
+ if (uri != null && uri.length() == 0) {
+ uri = null;
+ }
+
+ if (uri != null) {
+
+ if (document == null) {
+ document = documents.get(uri);
+ }
+
+ document.add(new Field(SearchFields.BINDING_FIELD, uri, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ return document == null ? FAKE_DOCUMENT : document;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+ public Object getDocumentKey(Object obj) {
+
+ if (obj instanceof Binding) {
+ Binding binding = (Binding)obj;
+ String uri = binding.getURI();
+
+ if (uri != null && uri.length() == 0) {
+ return null;
+ }
+
+ return uri;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ComponentDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ComponentDocumentProcessor.java
new file mode 100644
index 0000000000..28099f055c
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ComponentDocumentProcessor.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import org.apache.lucene.document.Field;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentProperty;
+import org.apache.tuscany.sca.assembly.ComponentReference;
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.assembly.Property;
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DocumentProcessor;
+import org.apache.tuscany.sca.domain.search.Result;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class ComponentDocumentProcessor implements DocumentProcessor {
+
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document doc,
+ String parent) {
+
+ if (object instanceof Component) {
+ Component component = (Component)object;
+ String uri = component.getURI();
+ String name = component.getName();
+
+ uri = (uri == null ? "" : uri) + (name == null ? "" : name);
+
+ if (uri.length() == 0) {
+ uri = null;
+ }
+
+ if (uri != null) {
+
+ if (doc == null) {
+ doc = documents.get(uri);
+ }
+
+ parent +=
+ DomainPathAnalyzer.PATH_SEPARATOR + SearchFields.COMPONENT_FIELD
+ + DomainPathAnalyzer.TYPE_SEPARATOR
+ + uri
+ + DomainPathAnalyzer.URI_SEPARATOR
+ + component.getName();
+
+ doc.add(new Field(SearchFields.COMPONENT_FIELD, uri, Field.Store.YES, Field.Index.ANALYZED));
+
+ for (ComponentService service : component.getServices()) {
+ Document serviceDoc = documents.get(uri + ':' + service.getName());
+
+ serviceDoc.add(new Field(SearchFields.SERVICE_NAME_FIELD, service.getName(), Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ InterfaceContract interfaceContract = service.getInterfaceContract();
+
+ if (interfaceContract != null) {
+
+ for (Operation operation : interfaceContract.getInterface().getOperations()) {
+
+ serviceDoc.add(new Field(SearchFields.SERVICE_INTERFACE_FIELD, operation.getName(),
+ Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ for (Operation operation : interfaceContract.getCallbackInterface().getOperations()) {
+
+ serviceDoc.add(new Field(SearchFields.SERVICE_INTERFACE_CALLBACK_FIELD,
+ operation.getName(), Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ serviceDoc.add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ for (ComponentReference reference : component.getReferences()) {
+ Document referenceDoc = documents.get(uri + ':' + reference.getName());
+
+ referenceDoc.add(new Field(SearchFields.REFERENCE_NAME_FIELD, reference.getName(), Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ InterfaceContract interfaceContract = reference.getInterfaceContract();
+
+ if (interfaceContract != null) {
+
+ for (Operation operation : interfaceContract.getInterface().getOperations()) {
+
+ referenceDoc.add(new Field(SearchFields.REFERENCE_INTERFACE_FIELD, operation.getName(),
+ Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ for (Operation operation : interfaceContract.getCallbackInterface().getOperations()) {
+
+ referenceDoc.add(new Field(SearchFields.REFERENCE_INTERFACE_CALLBACK_FIELD, operation
+ .getName(), Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ referenceDoc
+ .add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ Document implementationDoc =
+ parentProcessor.process(parentProcessor, documents, component.getImplementation(), null, parent);
+
+ if (uri != null && implementationDoc != null) {
+
+ implementationDoc.add(new Field(SearchFields.PARENT_FIELD, uri, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ for (ComponentProperty componentProperty : component.getProperties()) {
+
+ Property property = componentProperty.getProperty();
+
+ if (property != null) {
+ Document propertyDoc = parentProcessor.process(parentProcessor, documents, property, null, parent);
+
+ if (uri != null) {
+ propertyDoc.add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ }
+
+ return doc == null ? FAKE_DOCUMENT : doc;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+ public Object getDocumentKey(Object obj) {
+
+ if (obj instanceof Component) {
+ Component component = (Component)obj;
+ String uri = component.getURI();
+ String name = component.getName();
+
+ uri = (uri == null ? "" : uri) + (name == null ? "" : name);
+
+ if (uri.length() == 0) {
+ return null;
+ }
+
+ return uri;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+ public Result processDocument(org.apache.lucene.document.Document document, Result result) {
+ String componentName = document.get(SearchFields.COMPONENT_FIELD);
+
+ if (componentName != null) {
+
+ }
+
+ return null;
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ComponentTypeDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ComponentTypeDocumentProcessor.java
new file mode 100644
index 0000000000..6c6f7e2194
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ComponentTypeDocumentProcessor.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import org.apache.lucene.document.Field;
+import org.apache.tuscany.sca.assembly.ComponentType;
+import org.apache.tuscany.sca.assembly.Property;
+import org.apache.tuscany.sca.assembly.Reference;
+import org.apache.tuscany.sca.assembly.Service;
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DocumentProcessor;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class ComponentTypeDocumentProcessor implements DocumentProcessor {
+
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document doc,
+ String parent) {
+
+ if (object instanceof ComponentType) {
+ ComponentType componentType = (ComponentType)object;
+ String uri = componentType.getURI();
+
+ if (uri != null && uri.length() == 0) {
+ uri = null;
+ }
+
+ if (doc == null) {
+
+ if (uri != null) {
+ doc = documents.get(uri);
+
+ } else {
+ doc = FAKE_DOCUMENT;
+ }
+
+ }
+
+ if (uri != null) {
+
+ parent +=
+ DomainPathAnalyzer.PATH_SEPARATOR + SearchFields.COMPONENT_TYPE_FIELD
+ + DomainPathAnalyzer.TYPE_SEPARATOR
+ + uri;
+
+ doc.add(new Field(SearchFields.COMPONENT_TYPE_FIELD, uri, Field.Store.YES, Field.Index.ANALYZED));
+
+ for (Service service : componentType.getServices()) {
+ Document serviceDoc = documents.get(uri + ':' + service.getName());
+
+ serviceDoc.add(new Field(SearchFields.SERVICE_NAME_FIELD, service.getName(), Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ InterfaceContract interfaceContract = service.getInterfaceContract();
+
+ if (interfaceContract != null) {
+
+ Interface interfac = interfaceContract.getInterface();
+
+ if (interfac != null) {
+
+ for (Operation operation : interfac.getOperations()) {
+
+ serviceDoc.add(new Field(SearchFields.SERVICE_INTERFACE_FIELD, operation.getName(),
+ Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ interfac = interfaceContract.getCallbackInterface();
+
+ if (interfac != null) {
+
+ for (Operation operation : interfac.getOperations()) {
+
+ serviceDoc.add(new Field(SearchFields.SERVICE_INTERFACE_CALLBACK_FIELD, operation
+ .getName(), Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ }
+
+ serviceDoc.add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ for (Reference reference : componentType.getReferences()) {
+ Document referenceDoc = documents.get(componentType.getURI() + ':' + reference.getName());
+
+ referenceDoc.add(new Field(SearchFields.REFERENCE_NAME_FIELD, reference.getName(), Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ InterfaceContract interfaceContract = reference.getInterfaceContract();
+
+ if (interfaceContract != null) {
+
+ for (Operation operation : interfaceContract.getInterface().getOperations()) {
+
+ referenceDoc.add(new Field(SearchFields.REFERENCE_INTERFACE_FIELD, operation.getName(),
+ Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ for (Operation operation : interfaceContract.getCallbackInterface().getOperations()) {
+
+ referenceDoc.add(new Field(SearchFields.REFERENCE_INTERFACE_CALLBACK_FIELD, operation
+ .getName(), Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ referenceDoc
+ .add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ for (Property property : componentType.getProperties()) {
+ Document propertyDoc = parentProcessor.process(parentProcessor, documents, property, null, parent);
+
+ if (uri != null) {
+
+ propertyDoc
+ .add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ return doc;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+ public Object getDocumentKey(Object object) {
+
+ if (object instanceof ComponentType) {
+ ComponentType componentType = (ComponentType)object;
+ String uri = componentType.getURI();
+
+ if (uri == null || uri.length() == 0) {
+ return null;
+
+ } else {
+ return uri;
+ }
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/CompositeDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/CompositeDocumentProcessor.java
new file mode 100644
index 0000000000..07002daa8d
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/CompositeDocumentProcessor.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import javax.xml.namespace.QName;
+
+import org.apache.lucene.document.Field;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DocumentProcessor;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class CompositeDocumentProcessor implements DocumentProcessor {
+
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document doc,
+ String parent) {
+
+ if (object instanceof Composite) {
+ Composite composite = (Composite)object;
+ QName name = composite.getName();
+ String uri = (name == null ? "" : name.getNamespaceURI() + ';' + name.getLocalPart());
+
+ if (uri.length() == 0) {
+ uri = null;
+
+ } else if (doc == null) {
+ doc = documents.get(uri);
+ }
+
+ if (uri != null) {
+ parent +=
+ DomainPathAnalyzer.PATH_SEPARATOR + SearchFields.COMPOSITE_FIELD
+ + DomainPathAnalyzer.TYPE_SEPARATOR
+ + uri;
+ }
+
+ for (Component component : composite.getComponents()) {
+
+ Document componentDoc = parentProcessor.process(parentProcessor, documents, component, null, parent);
+
+ if (uri != null) {
+
+ componentDoc
+ .add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ if (uri != null) {
+
+ doc.add(new Field(SearchFields.COMPOSITE_FIELD, uri, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ for (Composite include : composite.getIncludes()) {
+ Document compositeDoc = parentProcessor.process(parentProcessor, documents, include, null, parent);
+
+ if (uri != null) {
+
+ compositeDoc.add(new Field(SearchFields.INCLUDEDBY_FIELD, uri, Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ for (Component component : composite.getComponents()) {
+ Document componentDoc = parentProcessor.process(parentProcessor, documents, component, null, parent);
+
+ if (uri != null) {
+
+ componentDoc
+ .add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ return doc == null ? FAKE_DOCUMENT : doc;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+ public Object getDocumentKey(Object object) {
+
+ if (object instanceof Composite) {
+ Composite composite = (Composite)object;
+ String uri = composite.getURI();
+ QName name = composite.getName();
+
+ uri = (uri == null ? "" : uri) + (name == null ? "" : name.toString());
+
+ return uri.length() == 0 ? null : uri;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ContributionDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ContributionDocumentProcessor.java
new file mode 100644
index 0000000000..7735f9ef1e
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ContributionDocumentProcessor.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import org.apache.lucene.document.Field;
+
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.contribution.Artifact;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DocumentProcessor;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class ContributionDocumentProcessor implements DocumentProcessor {
+
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document doc,
+ String parent) {
+
+ if (object instanceof Contribution) {
+ Contribution contribution = (Contribution)object;
+ String uri = contribution.getURI();
+
+ if (uri != null) {
+
+ if (uri.length() == 0) {
+ uri = null;
+
+ } else {
+
+ parent +=
+ Character.toString(DomainPathAnalyzer.PATH_START) + SearchFields.CONTRIBUTION_FIELD
+ + DomainPathAnalyzer.TYPE_SEPARATOR
+ + uri;
+
+ }
+
+ }
+
+ if (uri != null) {
+
+ if (doc == null) {
+ doc = documents.get(uri);
+ }
+
+ doc.add(new Field(SearchFields.CONTRIBUTION_FIELD, uri, Field.Store.YES, Field.Index.ANALYZED));
+
+ } else {
+ doc = FAKE_DOCUMENT;
+ }
+
+ for (Artifact artifact : contribution.getArtifacts()) {
+ Document artifactDoc = parentProcessor.process(parentProcessor, documents, artifact, null, parent);
+
+ if (uri != null) {
+
+ artifactDoc
+ .add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES, Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ // for (Import imprt : contribution.getImports()) {
+ // Document importDoc = processors.process(processors, documents,
+ // imprt, null);
+ //
+ // if (uri != null) {
+ //
+ // importDoc.add(new Field(SearchFields.IMPORTEDBY_FIELD, uri,
+ // Field.Store.YES, Field.Index.ANALYZED));
+ //
+ // }
+ //
+ // }
+ //
+ // for (Export export : contribution.getExports()) {
+ // Document exportDoc = processors.process(processors, documents,
+ // export, null);
+ //
+ // if (uri != null) {
+ //
+ // exportDoc.add(new Field(SearchFields.EXPORTEDBY_FIELD, uri,
+ // Field.Store.YES, Field.Index.ANALYZED));
+ //
+ // }
+ //
+ // }
+
+ if (!object.getClass().getSimpleName().contains("Workspace")) {
+
+ for (Composite composite : contribution.getDeployables()) {
+ Document compositeDoc =
+ parentProcessor.process(parentProcessor, documents, composite, null, parent);
+
+ if (uri != null) {
+
+ compositeDoc.add(new Field(SearchFields.PARENT_FIELD, parent, Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ }
+
+ }
+
+ }
+
+ return doc;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+ public Object getDocumentKey(Object object) {
+
+ if (object instanceof Contribution) {
+ Contribution contribution = (Contribution)object;
+ String uri = contribution.getURI();
+
+ if (uri != null && uri.length() == 0) {
+ return null;
+ }
+
+ return uri;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DefaultFileContent.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DefaultFileContent.java
new file mode 100644
index 0000000000..1c32d0cb5e
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DefaultFileContent.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class DefaultFileContent implements FileContent {
+
+ final private URL url;
+
+ public DefaultFileContent(URL url) {
+ this.url = url;
+ }
+
+ public FileContent[] getChildren() {
+ return new FileContent[0];
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return this.url.openStream();
+ }
+
+ public String getName() {
+ return this.url.getFile();
+ }
+
+ public String getPath() {
+ return this.url.getPath();
+ }
+
+ public boolean isLeaf() {
+ return false;
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DefaultFileDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DefaultFileDocumentProcessor.java
new file mode 100644
index 0000000000..e997b8f1f2
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DefaultFileDocumentProcessor.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+import org.apache.lucene.document.Field;
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DocumentProcessor;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class DefaultFileDocumentProcessor implements DocumentProcessor {
+
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document doc,
+ String parent) {
+
+ if (object instanceof FileContent) {
+ FileContent file = (FileContent)object;
+
+ Reader reader;
+ try {
+ reader = new InputStreamReader(file.getInputStream());
+
+ if (doc == null) {
+ doc = documents.get(file.getPath());
+ }
+
+ doc.add(new Field(SearchFields.FILE_CONTENT_FIELD, reader));
+
+ doc.add(new Field(SearchFields.FILE_CONTENT_FIELD, "", Field.Store.YES, Field.Index.ANALYZED));
+
+ return doc;
+
+ } catch (IOException e) {
+ // ignore the file
+ }
+
+ }
+
+ return null;
+
+ }
+
+ public Object getDocumentKey(Object object) {
+
+ if (object instanceof File) {
+ File file = (File)object;
+ String path = file.getPath();
+
+ if (path != null && path.length() == 0) {
+ return null;
+ }
+
+ return path;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/Document.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/Document.java
new file mode 100644
index 0000000000..ad50468ed6
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/Document.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.LinkedList;
+
+import org.apache.lucene.document.Fieldable;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class Document {
+
+ private Hashtable<String, Hashtable<String, Fieldable>> fieldablesTable =
+ new Hashtable<String, Hashtable<String, Fieldable>>();
+
+ private Hashtable<String, LinkedList<Fieldable>> readerMap = new Hashtable<String, LinkedList<Fieldable>>();;
+
+ public Document() {
+ // empty constructor
+ }
+
+ public void add(Fieldable fieldable) {
+
+ String strValue = fieldable.stringValue();
+
+ if (strValue != null) {
+
+ Hashtable<String, Fieldable> fieldables = this.fieldablesTable.get(fieldable.name());
+
+ if (fieldables == null) {
+ fieldables = new Hashtable<String, Fieldable>();
+ this.fieldablesTable.put(fieldable.name(), fieldables);
+
+ }
+
+ fieldables.put(strValue, fieldable);
+
+ } else {
+
+ LinkedList<Fieldable> fieldables = this.readerMap.get(fieldable.name());
+
+ if (fieldables == null) {
+ fieldables = new LinkedList<Fieldable>();
+ this.readerMap.put(fieldable.name(), fieldables);
+
+ }
+
+ fieldables.add(fieldable);
+
+ }
+
+ }
+
+ public org.apache.lucene.document.Document createLuceneDocument() {
+ org.apache.lucene.document.Document doc = new org.apache.lucene.document.Document();
+
+ for (Hashtable<String, Fieldable> fieldables : this.fieldablesTable.values()) {
+
+ for (Fieldable fieldable : fieldables.values()) {
+ doc.add(fieldable);
+ }
+
+ }
+
+ for (LinkedList<Fieldable> fieldables : this.readerMap.values()) {
+
+ for (Fieldable fieldable : fieldables) {
+ doc.add(fieldable);
+ }
+
+ }
+
+ return doc;
+
+ }
+
+ public Collection<String> getFieldValues(String field) {
+ Hashtable<String, Fieldable> fieldables = this.fieldablesTable.get(field);
+
+ if (fieldables != null) {
+ return fieldables.keySet();
+ }
+
+ return Collections.emptyList();
+
+ }
+
+ public boolean containsField(String field) {
+ return this.fieldablesTable.containsKey(field);
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainPathAnalyzer.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainPathAnalyzer.java
new file mode 100644
index 0000000000..c0b5bcb218
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainPathAnalyzer.java
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.Tokenizer;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class DomainPathAnalyzer extends Analyzer {
+
+ final public static char PATH_START = '\u0001';
+
+ final public static char PATH_SEPARATOR = '\u0002';
+
+ final public static char TYPE_SEPARATOR = '\u0003';
+
+ final public static char URI_SEPARATOR = '\u0004';
+
+ final public static char ARCHIVE_SEPARATOR = '!';
+
+ static class DomainPathTokenizer extends Tokenizer {
+
+ private int offset = 0, bufferIndex = 0, dataLen = 0;
+ private static final int MAX_WORD_LEN = 1024;
+ private static final int IO_BUFFER_SIZE = 4096;
+ private final char[] ioBuffer = new char[IO_BUFFER_SIZE];
+ private boolean typeCharFound = false;
+ private boolean uriCharFound = false;
+
+ public DomainPathTokenizer(Reader reader) {
+ super(reader);
+ }
+
+ @Override
+ public void reset() throws IOException {
+ super.reset();
+
+ typeCharFound = false;
+ uriCharFound = false;
+
+ }
+
+ @Override
+ public void reset(Reader input) throws IOException {
+ super.reset(input);
+
+ uriCharFound = false;
+ typeCharFound = false;
+
+ }
+
+ @Override
+ public Token next(Token reusableToken) throws IOException {
+ assert reusableToken != null;
+ reusableToken.clear();
+ int length = 0;
+ int start = bufferIndex;
+ char[] buffer = reusableToken.termBuffer();
+
+ boolean lowercaseCharFound = false;
+ boolean digitFound = false;
+
+ while (true) {
+
+ if (bufferIndex >= dataLen) {
+ offset += dataLen;
+ int incr;
+
+ if (lowercaseCharFound || length == 0) {
+ incr = 0;
+
+ } else {
+ incr = 2;
+ ioBuffer[0] = ioBuffer[bufferIndex - 1];
+ ioBuffer[1] = ioBuffer[bufferIndex];
+
+ }
+
+ dataLen = input.read(ioBuffer, incr, ioBuffer.length - incr);
+ if (dataLen == -1) {
+ if (length > 0)
+ break;
+ else
+ return null;
+ }
+ bufferIndex = incr;
+ dataLen += incr;
+
+ }
+
+ final char c = ioBuffer[bufferIndex++];
+ boolean breakChar = true;
+ boolean includeChar = false;
+
+ if (c == PATH_START || c == PATH_SEPARATOR) {
+
+ if (length == 0) {
+ includeChar = true;
+
+ } else {
+ bufferIndex--;
+ }
+
+ typeCharFound = false;
+ uriCharFound = false;
+
+ } else if (c == TYPE_SEPARATOR && !typeCharFound || c == URI_SEPARATOR && !uriCharFound) {
+ length = 0;
+ breakChar = false;
+ lowercaseCharFound = false;
+ digitFound = false;
+
+ } else {
+
+ if (Character.isDigit(c)) {
+
+ if (digitFound || length == 0) {
+ breakChar = false;
+ digitFound = true;
+
+ } else {
+ bufferIndex--;
+ }
+
+ // TODO: normalize accent, it does not index accents for
+ // now
+ } else if (c >= 65 && c <= 90 || c >= 97 && c <= 122) {
+
+ if (digitFound) {
+ bufferIndex--;
+
+ } else if (Character.isLowerCase(c)) {
+
+ if (!(lowercaseCharFound || length <= 1)) {
+ length--;
+ bufferIndex -= 2;
+
+ } else {
+ lowercaseCharFound = true;
+ breakChar = false;
+
+ }
+
+ } else if (!lowercaseCharFound) { // && uppercase
+ breakChar = false;
+
+ } else {
+ bufferIndex--;
+ }
+
+ }
+
+ }
+
+ if (!breakChar || includeChar) {
+
+ if (length == 0) // start of token
+ start = offset + bufferIndex - 1;
+ else if (length == buffer.length)
+ buffer = reusableToken.resizeTermBuffer(1 + length);
+
+ if (c == TYPE_SEPARATOR && !typeCharFound) {
+ typeCharFound = true;
+
+ } else if (c == URI_SEPARATOR && !uriCharFound) {
+ typeCharFound = true;
+
+ } else {
+ buffer[length++] = Character.toLowerCase(c); // buffer
+ // it,
+ // normalized
+ }
+
+ if (length == MAX_WORD_LEN || (breakChar && length > 0)) // buffer
+ // overflow!
+ break;
+
+ } else if (length > 0) {// at non-Letter w/ chars
+
+ break; // return 'em
+
+ }
+
+ }
+
+ reusableToken.setTermLength(length);
+ reusableToken.setStartOffset(start);
+ reusableToken.setEndOffset(start + length);
+
+ return reusableToken;
+
+ }
+ }
+
+ public TokenStream tokenStream(String fieldName, Reader reader) {
+ return new DomainPathTokenizer(reader);
+ }
+
+ public TokenStream reusableTokenStream(String fieldName, Reader reader) throws IOException {
+ Tokenizer tokenizer = (Tokenizer)getPreviousTokenStream();
+ if (tokenizer == null) {
+ tokenizer = new DomainPathTokenizer(reader);
+ setPreviousTokenStream(tokenizer);
+ } else
+ tokenizer.reset(reader);
+ return tokenizer;
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchAnalyzer.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchAnalyzer.java
new file mode 100644
index 0000000000..1514a13096
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchAnalyzer.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import org.apache.lucene.analysis.PerFieldAnalyzerWrapper;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class DomainSearchAnalyzer extends PerFieldAnalyzerWrapper {
+
+ public DomainSearchAnalyzer() {
+ super(new NamingAnalyzer());
+
+ addAnalyzer(SearchFields.PARENT_FIELD, new DomainPathAnalyzer());
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchDocumentProcessorsMap.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchDocumentProcessorsMap.java
new file mode 100644
index 0000000000..554da34ea1
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchDocumentProcessorsMap.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentType;
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.assembly.Property;
+import org.apache.tuscany.sca.contribution.Artifact;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.domain.search.DocumentProcessorsMap;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class DomainSearchDocumentProcessorsMap extends DocumentProcessorsMap {
+
+ private static final long serialVersionUID = -4651637686945322606L;
+
+ public DomainSearchDocumentProcessorsMap() {
+ put(Contribution.class, new ContributionDocumentProcessor());
+ put(Artifact.class, new ArtifactDocumentProcessor());
+ put(Property.class, new PropertyDocumentProcessor());
+ put(ComponentType.class, new ComponentTypeDocumentProcessor());
+ put(Binding.class, new BindingDocumentProcessor());
+ put(Component.class, new ComponentDocumentProcessor());
+ put(Composite.class, new CompositeDocumentProcessor());
+ put(FileContent.class, new DomainSearchFileDocumentProcessor());
+ put(Property.class, new PropertyDocumentProcessor());
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchFileDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchFileDocumentProcessor.java
new file mode 100644
index 0000000000..ae6821e8ed
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchFileDocumentProcessor.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class DomainSearchFileDocumentProcessor extends FileDocumentProcessor {
+
+ private static final long serialVersionUID = -2725616937948969598L;
+
+ public DomainSearchFileDocumentProcessor() {
+ add(new ZipDocumentProcessor());
+ add(new DefaultFileDocumentProcessor());
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchFormatter.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchFormatter.java
new file mode 100644
index 0000000000..e9ddf036a0
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchFormatter.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import org.apache.lucene.search.highlight.Formatter;
+import org.apache.lucene.search.highlight.TokenGroup;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class DomainSearchFormatter implements Formatter {
+
+ final public static String HIGHLIGHT_START = "\u0005\u0005\u0006";
+
+ final public static String HIGHLIGHT_END = "\u0006\u0005\u0005";
+
+ private StringBuilder sb = new StringBuilder();
+
+ public String highlightTerm(String originalText, TokenGroup tokenGroup) {
+
+ if (tokenGroup.getTotalScore() > 0) {
+ sb.setLength(0);
+
+ sb.append(HIGHLIGHT_START).append(originalText).append(HIGHLIGHT_END);
+
+ return sb.toString();
+
+ } else {
+ return originalText;
+ }
+
+ }
+
+ public static boolean isHighlighted(String text) {
+ int start = text.indexOf(HIGHLIGHT_START);
+ int end = text.indexOf(HIGHLIGHT_END);
+
+ if (start < end && start != -1) {
+ start = text.indexOf(HIGHLIGHT_START, start + 1);
+
+ if (start > end || start == -1) {
+ return true;
+ }
+
+ }
+
+ return false;
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchImpl.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchImpl.java
new file mode 100644
index 0000000000..8004ac6faa
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchImpl.java
@@ -0,0 +1,371 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.queryParser.MultiFieldQueryParser;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.lucene.store.RAMDirectory;
+import org.apache.lucene.store.SimpleFSLockFactory;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DomainSearch;
+import org.apache.tuscany.sca.domain.search.IndexException;
+import org.apache.tuscany.sca.domain.search.Result;
+import org.osoa.sca.annotations.AllowsPassByReference;
+import org.osoa.sca.annotations.Property;
+import org.osoa.sca.annotations.Scope;
+
+/**
+ * @version $Rev$ $Date$
+ */
+@Scope("COMPOSITE")
+public class DomainSearchImpl implements DomainSearch {
+
+ @Property
+ public String indexDirectoryPath;
+
+ private Directory dir;
+
+ private Analyzer analyzer = new DomainSearchAnalyzer();
+
+ private MultiFieldQueryParser qp =
+ new MultiFieldQueryParser(new String[] {SearchFields.ARTIFACT_FIELD, SearchFields.BINDING_FIELD,
+ SearchFields.COMPONENT_FIELD, SearchFields.COMPOSITE_FIELD,
+ SearchFields.CONTRIBUTION_FIELD, SearchFields.EXPORTEDBY_FIELD,
+ SearchFields.FILE_CONTENT_FIELD, SearchFields.IMPLEMENTS_FIELD,
+ SearchFields.IMPORTEDBY_FIELD, SearchFields.INCLUDEDBY_FIELD,
+ SearchFields.PROPERTY_KEY_FIELD, SearchFields.REFERENCE_FIELD,
+ SearchFields.REFERENCE_INTERFACE_CALLBACK_FIELD,
+ SearchFields.REFERENCE_INTERFACE_FIELD,
+ SearchFields.REFERENCE_NAME_FIELD, SearchFields.SERVICE_FIELD,
+ SearchFields.SERVICE_INTERFACE_CALLBACK_FIELD,
+ SearchFields.SERVICE_INTERFACE_FIELD, SearchFields.SERVICE_NAME_FIELD,
+ SearchFields.TYPE_FIELD, SearchFields.VALUE_FIELD}, this.analyzer);
+
+ public DomainSearchImpl() {
+ this.qp.setAllowLeadingWildcard(true);
+ }
+
+ private Directory getIndexDirectory() throws IOException {
+
+ if (this.dir == null) {
+
+ if (this.indexDirectoryPath == null || this.indexDirectoryPath.length() == 0) {
+ this.dir = new RAMDirectory();
+
+ } else {
+
+ try {
+ this.dir =
+ FSDirectory.getDirectory(new File(this.indexDirectoryPath),
+ new SimpleFSLockFactory(this.indexDirectoryPath));
+
+ } catch (IOException e) {
+ System.err.println("Could not open index at " + this.indexDirectoryPath);
+
+ throw e;
+
+ }
+
+ }
+
+ }
+
+ return this.dir;
+
+ }
+
+ @AllowsPassByReference
+ public void addContribution(Contribution contribution) throws IndexException {
+
+ IndexWriter indexWriter = null;
+
+ try {
+ indexWriter = new IndexWriter(getIndexDirectory(), this.analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
+
+ contributionAdded(contribution, indexWriter);
+
+ indexWriter.commit();
+
+ } catch (Exception e) {
+
+ if (indexWriter != null) {
+
+ try {
+ indexWriter.rollback();
+
+ } catch (Exception e1) {
+ // ignore exception
+ }
+
+ }
+
+ throw new IndexException(e.getMessage(), e);
+
+ } finally {
+
+ if (indexWriter != null) {
+
+ try {
+ indexWriter.close();
+
+ } catch (Exception e) {
+ // ignore exception
+ }
+
+ }
+
+ }
+
+ }
+
+ @AllowsPassByReference
+ public void removeContribution(Contribution contribution) throws IndexException {
+
+ IndexWriter indexWriter = null;
+
+ if (indexExists()) {
+
+ try {
+ indexWriter = new IndexWriter(getIndexDirectory(), this.analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
+
+ contributionRemoved(contribution, indexWriter);
+
+ indexWriter.commit();
+
+ } catch (Exception e) {
+
+ if (indexWriter != null) {
+
+ try {
+ indexWriter.rollback();
+
+ } catch (Exception e1) {
+ // ignore exception
+ }
+
+ }
+
+ throw new IndexException(e.getMessage(), e);
+
+ } finally {
+
+ if (indexWriter != null) {
+
+ try {
+ indexWriter.close();
+
+ } catch (Exception e) {
+ // ignore exception
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ private void contributionRemoved(Contribution contribution, IndexWriter indexWriter) throws IndexException {
+
+ String contributionURI = contribution.getURI();
+ StringBuilder sb = new StringBuilder(SearchFields.PARENT_FIELD);
+ sb.append(":\"");
+ sb.append(DomainPathAnalyzer.PATH_START);
+ sb.append(contributionURI);
+ sb.append("\" OR ");
+ sb.append(SearchFields.CONTRIBUTION_FIELD);
+ sb.append(":\"");
+ sb.append(contributionURI);
+ sb.append('"');
+
+ try {
+ Query query = this.qp.parse(sb.toString());
+ indexWriter.deleteDocuments(query);
+
+ } catch (ParseException e) {
+ // ignore exception
+
+ } catch (CorruptIndexException ex) {
+ throw new IndexException(ex.getMessage(), ex);
+
+ } catch (IOException ex) {
+ throw new IndexException(ex.getMessage(), ex);
+ }
+
+ }
+
+ private void contributionAdded(Contribution contribution, IndexWriter indexWriter) throws IndexException {
+ DomainSearchDocumentProcessorsMap docProcessors = new DomainSearchDocumentProcessorsMap();
+ DocumentMap docs = new DocumentMap();
+
+ try {
+ docProcessors.process(docProcessors, docs, contribution, null, "");
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // FileWriter writer = new FileWriter("indexed.txt");
+ for (Document doc : docs.values()) {
+ org.apache.lucene.document.Document luceneDoc = doc.createLuceneDocument();
+ // writer.write(luceneDoc.toString());
+ // writer.write('\n');
+ // writer.write('\n');
+
+ try {
+ indexWriter.addDocument(luceneDoc);
+
+ } catch (CorruptIndexException e) {
+ throw new IndexException(e.getMessage(), e);
+
+ } catch (IOException e) {
+ throw new IndexException(e.getMessage(), e);
+ }
+
+ }
+ // writer.close();
+
+ }
+
+ @AllowsPassByReference
+ public void updateContribution(Contribution oldContribution, Contribution contribution) throws IndexException {
+
+ IndexWriter indexWriter = null;
+
+ try {
+ indexWriter = new IndexWriter(getIndexDirectory(), this.analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
+
+ contributionRemoved(oldContribution, indexWriter);
+ contributionAdded(contribution, indexWriter);
+
+ indexWriter.commit();
+
+ } catch (Exception e) {
+
+ if (indexWriter != null) {
+
+ try {
+ indexWriter.rollback();
+
+ } catch (Exception e1) {
+ // ignore exception
+ }
+
+ }
+
+ throw new IndexException(e.getMessage(), e);
+
+ } finally {
+
+ if (indexWriter != null) {
+
+ try {
+ indexWriter.close();
+
+ } catch (Exception e) {
+ // ignore exception
+ }
+
+ }
+
+ }
+
+ }
+
+ public Result[] parseAndSearch(String searchQuery, final boolean highlight) throws IndexException, ParseException {
+ return search(this.qp.parse(searchQuery), highlight);
+ }
+
+ public Result[] search(Query searchQuery, boolean highlight) throws IndexException {
+
+ try {
+ final IndexSearcher searcher = new IndexSearcher(getIndexDirectory());
+ DomainSearchResultProcessor resultProcessor =
+ new DomainSearchResultProcessor(new DomainSearchResultFactory());
+ TopDocs topDocs = searcher.search(searchQuery, 1000);
+
+ int indexed = 0;
+ HashSet<String> set = new HashSet<String>();
+ for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
+ org.apache.lucene.document.Document luceneDocument = searcher.doc(scoreDoc.doc);
+
+ resultProcessor.process(luceneDocument, null);
+
+ indexed++;
+ set.add(luceneDocument.toString());
+
+ }
+
+ Result[] results = resultProcessor.createResultRoots();
+
+ if (highlight) {
+
+ for (Result result : results) {
+ HighlightingUtil.highlightResult(result, searchQuery);
+ }
+
+ }
+
+ return results;
+
+ } catch (CorruptIndexException ex) {
+ throw new IndexException(ex.getMessage(), ex);
+
+ } catch (IOException ex) {
+ throw new IndexException(ex.getMessage(), ex);
+ }
+
+ }
+
+ public String highlight(String field, String text, String searchQuery) throws ParseException {
+ final Query query = this.qp.parse(searchQuery);
+
+ return HighlightingUtil.highlight(field, query, text);
+
+ }
+
+ public boolean indexExists() {
+
+ if ((this.indexDirectoryPath == null || this.indexDirectoryPath.length() == 0) && this.dir == null) {
+
+ return false;
+
+ } else {
+ return this.dir != null || IndexReader.indexExists(new File(this.indexDirectoryPath));
+ }
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchResultFactory.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchResultFactory.java
new file mode 100644
index 0000000000..6a5b875586
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchResultFactory.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class DomainSearchResultFactory extends PriorityFieldListResultFactory {
+
+ private static final long serialVersionUID = -7421799172738469027L;
+
+ public DomainSearchResultFactory() {
+ add(SearchFields.COMPOSITE_FIELD);
+ add(SearchFields.COMPONENT_FIELD);
+ add(SearchFields.COMPONENT_TYPE_FIELD);
+ add(SearchFields.CONTRIBUTION_FIELD);
+ add(SearchFields.BINDING_FIELD);
+ add(SearchFields.FILE_CONTENT_FIELD);
+ add(SearchFields.ARTIFACT_FIELD);
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchResultProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchResultProcessor.java
new file mode 100644
index 0000000000..ee2268b922
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/DomainSearchResultProcessor.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import org.apache.tuscany.sca.domain.search.Result;
+import org.apache.tuscany.sca.domain.search.ResultFactory;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class DomainSearchResultProcessor extends ResultProcessorList {
+
+ private static final long serialVersionUID = 792292814333612713L;
+
+ public DomainSearchResultProcessor(ResultFactory<? extends Result> resultFactory) {
+
+ super(new DomainSearchResultFactory());
+
+ add(new FileContentResultProcessor());
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileContent.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileContent.java
new file mode 100644
index 0000000000..923eff998a
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileContent.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public interface FileContent {
+
+ String getPath();
+
+ String getName();
+
+ FileContent[] getChildren();
+
+ boolean isLeaf();
+
+ InputStream getInputStream() throws IOException;
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileContentResultProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileContentResultProcessor.java
new file mode 100644
index 0000000000..f6253d6a17
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileContentResultProcessor.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+
+import org.apache.lucene.document.Document;
+import org.apache.tuscany.sca.domain.search.Result;
+import org.apache.tuscany.sca.domain.search.ResultProcessor;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class FileContentResultProcessor implements ResultProcessor {
+
+ public Result process(Document document, Result result) {
+
+ if (document.getFieldable(SearchFields.FILE_CONTENT_FIELD) != null) {
+ Reader reader;
+
+ ParentField parentField = new ParentField(document.get(SearchFields.PARENT_FIELD));
+
+ int lastParentElementIndex = parentField.getElementsCount() - 1;
+ String parentURI;
+
+ if (SearchFields.ARTIFACT_FIELD.equals(parentField.getElementType(lastParentElementIndex))) {
+ parentURI = parentField.getElementURI(lastParentElementIndex);
+
+ // if (parentURI.startsWith("jar:")) {
+
+ try {
+ reader = new InputStreamReader(new URL(parentURI).openStream());
+
+ } catch (IOException e) {
+ return result;
+ }
+
+ // } else {
+ //
+ // try {
+ // reader = new InputStreamReader(new FileInputStream(
+ // new File(parentURI + (parentURI.length() > 0 ? "/" : "") +
+ // name)));
+ //
+ // } catch (FileNotFoundException e) {
+ // return result;
+ // }
+ //
+ // }
+
+ try {
+
+ StringBuilder sb = new StringBuilder();
+ int c;
+
+ // TODO: load the chars into an array buffer instead of one
+ // at a
+ // time
+ while ((c = reader.read()) != -1) {
+ char character = (char)c;
+
+ if (!Character.isIdentifierIgnorable(character)) {
+ sb.append(character);
+ }
+
+ }
+
+ result.setValue(sb.toString());
+
+ } catch (Exception e) {
+ // ignore content loading, TODO: maybe it should return an
+ // error
+ // message as the content
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileDocumentProcessor.java
new file mode 100644
index 0000000000..553a5b57cd
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/FileDocumentProcessor.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.util.LinkedList;
+
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DocumentProcessor;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class FileDocumentProcessor extends LinkedList<DocumentProcessor> implements DocumentProcessor {
+
+ private static final long serialVersionUID = 7843338343970738591L;
+
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document doc,
+ String parent) {
+
+ if (object instanceof FileContent) {
+ FileContent file = (FileContent)object;
+
+ if (!file.isLeaf()) {
+
+ if (doc == null) {
+ doc = documents.get(SearchFields.FILE_CONTENT_FIELD + file.getPath());
+ }
+
+ // FileContent[] files = file.getChildren();
+
+ // for (FileContent childFile : files) {
+ // // Document fileDoc = parentProcessor.process(
+ // // parentProcessor, documents, childFile, null,
+ // // parent);
+ //
+ // Document fileDoc = null;
+ //
+ // fileDoc = process(this, documents, childFile, null, parent);
+ //
+ // if (fileDoc == null) {
+ // continue;
+ // }
+ //
+ // fileDoc.add(new Field(SearchFields.PARENT_FIELD, parent,
+ // Field.Store.YES, Field.Index.ANALYZED));
+ //
+ // }
+
+ return doc;
+
+ } else {
+
+ for (DocumentProcessor processor : this) {
+ Document newDoc = processor.process(this, documents, file, doc, parent);
+
+ if (newDoc != null) {
+ return newDoc;
+ }
+
+ }
+
+ }
+
+ }
+
+ return doc;
+
+ }
+
+ public Object getDocumentKey(Object object) {
+
+ if (object instanceof FileContent) {
+ FileContent file = (FileContent)object;
+ String path = file.getPath();
+
+ if (path != null && path.length() == 0) {
+ return null;
+ }
+
+ return SearchFields.FILE_CONTENT_FIELD + path;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/HighlightingUtil.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/HighlightingUtil.java
new file mode 100644
index 0000000000..ba8e1bf021
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/HighlightingUtil.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Map;
+
+import org.apache.lucene.analysis.CachingTokenFilter;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.highlight.Fragmenter;
+import org.apache.lucene.search.highlight.Highlighter;
+import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
+import org.apache.lucene.search.highlight.NullFragmenter;
+import org.apache.lucene.search.highlight.SimpleFragmenter;
+import org.apache.lucene.search.highlight.QueryScorer;
+import org.apache.tuscany.sca.domain.search.Result;
+
+/**
+ * @version $Rev$ $Date$
+ */
+final public class HighlightingUtil {
+
+ public static void highlightResult(Result result, Query query) {
+ highlightResult(result, query, new SimpleFragmenter(70));
+ }
+
+ public static void highlightResult(Result result, Query query, Fragmenter fragmenter) {
+ Map<String, Result> contents = result.getContents();
+
+ if (contents != null) {
+
+ for (Result content : contents.values()) {
+ highlightResult(content, query, fragmenter);
+ }
+
+ }
+
+ String highlightedText =
+ HighlightingUtil.bestFragmentHighlighted(result.getField(), query, result.getValue(), fragmenter);
+
+ // checks if something was highlighted before resetting the value
+ if (highlightedText != null && highlightedText.length() > 0) {
+ result.setValue(highlightedText);
+ }
+
+ }
+
+ public static String highlight(String field, Query query, String text) {
+ String highlightedText = bestFragmentHighlighted(field, query, text, new NullFragmenter());
+
+ if (highlightedText == null || text.length() >= highlightedText.length()) {
+ return text;
+ }
+
+ return highlightedText;
+
+ }
+
+ public static String bestFragmentHighlighted(String field, Query query, String text) throws IOException {
+ return bestFragmentHighlighted(field, query, text, new SimpleFragmenter(100));
+ }
+
+ public static String bestFragmentHighlighted(String field, Query query, String text, Fragmenter fragmenter) {
+
+ try {
+ CachingTokenFilter tokenStream =
+ new CachingTokenFilter(new DomainSearchAnalyzer().tokenStream(field, new StringReader(text)));
+
+ QueryScorer scorer = new QueryScorer(query, field, "");
+ scorer.init(tokenStream);
+
+ Highlighter highlighter =
+ new Highlighter(new DomainSearchFormatter(), scorer);
+ highlighter.setTextFragmenter(fragmenter);
+ tokenStream.reset();
+
+ try {
+ return highlighter.getBestFragments(tokenStream, text, 2, " ... ");
+
+ } catch (InvalidTokenOffsetsException e) {
+ // could not create fragments, return empty string
+ }
+
+ } catch (IOException ex) {
+ // should never happen
+ }
+
+ return "";
+
+ }
+
+ public static String replaceHighlightMarkupBy(CharSequence text, String startHighlight, String endHighlight) {
+ StringBuilder sb = new StringBuilder();
+ int start = 0;
+ int end = 0;
+
+ for (int i = 0; i < text.length(); i++) {
+ char c = text.charAt(i);
+
+ if (start > 0) {
+
+ if (c == DomainSearchFormatter.HIGHLIGHT_START.charAt(start)) {
+ start++;
+
+ if (start == DomainSearchFormatter.HIGHLIGHT_START.length()) {
+ sb.append(startHighlight);
+ start = 0;
+
+ }
+
+ } else {
+
+ for (int j = 0; j < start; j++) {
+ sb.append(DomainSearchFormatter.HIGHLIGHT_START.charAt(j));
+ }
+
+ start = 0;
+
+ }
+
+ } else if (end > 0) {
+
+ if (c == DomainSearchFormatter.HIGHLIGHT_END.charAt(end)) {
+ end++;
+
+ if (end == DomainSearchFormatter.HIGHLIGHT_END.length()) {
+ sb.append(endHighlight);
+ end = 0;
+
+ }
+
+ } else {
+
+ for (int j = 0; j < end; j++) {
+ sb.append(DomainSearchFormatter.HIGHLIGHT_END.charAt(j));
+ }
+
+ end = 0;
+
+ }
+
+ } else if (c == DomainSearchFormatter.HIGHLIGHT_START.charAt(0)) {
+ start = 1;
+
+ } else if (c == DomainSearchFormatter.HIGHLIGHT_END.charAt(0)) {
+ end = 1;
+
+ } else {
+ sb.append(c);
+ }
+
+ }
+
+ if (start > 0) {
+
+ for (int j = 0; j < start; j++) {
+ sb.append(DomainSearchFormatter.HIGHLIGHT_START.charAt(j));
+ }
+
+ } else if (end > 0) {
+
+ for (int j = 0; j < start; j++) {
+ sb.append(DomainSearchFormatter.HIGHLIGHT_END.charAt(j));
+ }
+
+ }
+
+ return sb.toString();
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/NamingAnalyzer.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/NamingAnalyzer.java
new file mode 100644
index 0000000000..2f06b179e4
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/NamingAnalyzer.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.Tokenizer;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class NamingAnalyzer extends Analyzer {
+
+ public TokenStream tokenStream(String fieldName, Reader reader) {
+ return new NamingTokenizer(reader);
+ }
+
+ public TokenStream reusableTokenStream(String fieldName, Reader reader) throws IOException {
+ Tokenizer tokenizer = (Tokenizer)getPreviousTokenStream();
+ if (tokenizer == null) {
+ tokenizer = new NamingTokenizer(reader);
+ setPreviousTokenStream(tokenizer);
+ } else
+ tokenizer.reset(reader);
+ return tokenizer;
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/NamingTokenizer.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/NamingTokenizer.java
new file mode 100644
index 0000000000..280039a67e
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/NamingTokenizer.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.Tokenizer;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class NamingTokenizer extends Tokenizer {
+
+ private int offset = 0, bufferIndex = 0, dataLen = 0;
+ private static final int MAX_WORD_LEN = 255;
+ private static final int IO_BUFFER_SIZE = 4096;
+ private final char[] ioBuffer = new char[IO_BUFFER_SIZE];
+
+ public NamingTokenizer(Reader reader) {
+ super(reader);
+ }
+
+ @Override
+ public Token next(Token reusableToken) throws IOException {
+ assert reusableToken != null;
+ reusableToken.clear();
+ int length = 0;
+ int start = bufferIndex;
+ char[] buffer = reusableToken.termBuffer();
+
+ boolean lowercaseCharFound = false;
+ boolean digitFound = false;
+
+ while (true) {
+
+ if (bufferIndex >= dataLen) {
+ offset += dataLen;
+ int incr;
+
+ if (lowercaseCharFound || length == 0) {
+ incr = 0;
+
+ } else {
+ incr = 2;
+ ioBuffer[0] = ioBuffer[bufferIndex - 1];
+ ioBuffer[1] = ioBuffer[bufferIndex];
+
+ }
+
+ dataLen = input.read(ioBuffer, incr, ioBuffer.length - incr);
+ if (dataLen == -1) {
+ if (length > 0)
+ break;
+ else
+ return null;
+ }
+ bufferIndex = incr;
+ dataLen += incr;
+
+ }
+
+ final char c = ioBuffer[bufferIndex++];
+ boolean breakChar = true;
+
+ if (Character.isDigit(c)) {
+
+ if (digitFound || length == 0) {
+ breakChar = false;
+ digitFound = true;
+
+ } else {
+ bufferIndex--;
+ }
+
+ // TODO: normalize accent, it does not index accents for now
+ } else if (c >= 65 && c <= 90 || c >= 97 && c <= 122) {
+
+ if (digitFound) {
+ bufferIndex--;
+
+ } else if (Character.isLowerCase(c)) {
+
+ if (!(lowercaseCharFound || length <= 1)) {
+ length--;
+ bufferIndex -= 2;
+
+ } else {
+ lowercaseCharFound = true;
+ breakChar = false;
+
+ }
+
+ } else if (!lowercaseCharFound) { // && uppercase
+ breakChar = false;
+
+ } else {
+ bufferIndex--;
+ }
+
+ }
+
+ if (!breakChar) {
+
+ if (length == 0) // start of token
+ start = offset + bufferIndex - 1;
+ else if (length == buffer.length)
+ buffer = reusableToken.resizeTermBuffer(1 + length);
+
+ buffer[length++] = Character.toLowerCase(c); // buffer it,
+ // normalized
+
+ if (length == MAX_WORD_LEN) // buffer overflow!
+ break;
+
+ } else if (length > 0) {// at non-Letter w/ chars
+
+ break; // return 'em
+
+ }
+
+ }
+
+ reusableToken.setTermLength(length);
+ reusableToken.setStartOffset(start);
+ reusableToken.setEndOffset(start + length);
+
+ return reusableToken;
+
+ }
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ParentField.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ParentField.java
new file mode 100644
index 0000000000..862db63b2c
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ParentField.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class ParentField implements Serializable {
+
+ private static final long serialVersionUID = -2090538050273088026L;
+
+ final private List<ParentFieldElement> elements;
+
+ public ParentField(String parentFieldValue) {
+ int length = parentFieldValue.length();
+
+ if (length == 0) {
+ this.elements = Collections.emptyList();
+
+ return;
+
+ }
+
+ this.elements = new ArrayList<ParentFieldElement>();
+
+ ParentFieldElement element = null;
+ StringBuilder sb = new StringBuilder();
+
+ for (int i = 0; i < length; i++) {
+ char c = parentFieldValue.charAt(i);
+
+ if (c == DomainPathAnalyzer.PATH_SEPARATOR || c == DomainPathAnalyzer.PATH_START) {
+
+ if (sb.length() > 0 || element != null) {
+
+ if (element == null) {
+ element = new ParentFieldElement();
+ }
+
+ if (element.type == null) {
+ element.type = "";
+ }
+
+ if (element.uri == null) {
+ element.uri = element.name = sb.toString();
+
+ } else {
+ element.name = sb.toString();
+ }
+
+ sb.setLength(0);
+ this.elements.add(element);
+ element = null;
+
+ }
+
+ } else if (c == DomainPathAnalyzer.TYPE_SEPARATOR) {
+
+ if (element == null) {
+ element = new ParentFieldElement();
+ }
+
+ element.type = sb.toString();
+
+ sb.setLength(0);
+
+ } else if (c == DomainPathAnalyzer.URI_SEPARATOR) {
+
+ if (element == null) {
+ element = new ParentFieldElement();
+ }
+
+ element.uri = sb.toString();
+
+ sb.setLength(0);
+
+ } else {
+ sb.append(c);
+ }
+
+ }
+
+ if (sb.length() > 0 || element != null) {
+
+ if (element == null) {
+ element = new ParentFieldElement();
+ }
+
+ if (element.type == null) {
+ element.type = "";
+ }
+
+ if (element.uri == null) {
+ element.uri = element.name = sb.toString();
+
+ } else {
+ element.name = sb.toString();
+ }
+
+ sb.setLength(0);
+ this.elements.add(element);
+ element = null;
+
+ }
+
+ }
+
+ public static String getURIPath(ParentField parentField) {
+ return getURIPath(parentField, System.getProperty("file.separator"));
+ }
+
+ public static String getURIPath(ParentField parentField, String pathSeparator) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(pathSeparator);
+ int elementsCount = parentField.getElementsCount();
+
+ for (int i = 0; i < elementsCount; i++) {
+ sb.append(parentField.getElementName(i));
+ sb.append(pathSeparator);
+
+ }
+
+ if (sb.length() > pathSeparator.length()) {
+ sb.setLength(sb.length() - pathSeparator.length());
+ }
+
+ return sb.toString();
+
+ }
+
+ public static int getParentElementsCount(String parent) {
+ int length = parent.length();
+
+ if (length == 0) {
+ return 0;
+ }
+
+ boolean pathSeparatorBefore = true;
+ int count = 1;
+
+ for (int i = 0; i < length - 1; i++) {
+ char c = parent.charAt(i);
+
+ if (c == DomainPathAnalyzer.PATH_SEPARATOR && !pathSeparatorBefore) {
+ pathSeparatorBefore = true;
+ count++;
+
+ } else {
+ pathSeparatorBefore = false;
+ }
+
+ }
+
+ return count;
+
+ }
+
+ public int getElementsCount() {
+ return this.elements.size();
+ }
+
+ public String getElementType(int index) {
+ return this.elements.get(index).type;
+ }
+
+ public String getElementURI(int index) {
+ return this.elements.get(index).uri;
+ }
+
+ public String getElementName(int index) {
+ return this.elements.get(index).name;
+ }
+
+ final private static class ParentFieldElement {
+
+ String type;
+
+ String uri;
+
+ String name;
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/PriorityFieldListResultFactory.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/PriorityFieldListResultFactory.java
new file mode 100644
index 0000000000..bd1912af49
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/PriorityFieldListResultFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.util.LinkedList;
+
+import org.apache.lucene.document.Document;
+import org.apache.tuscany.sca.domain.search.Result;
+import org.apache.tuscany.sca.domain.search.ResultFactory;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class PriorityFieldListResultFactory extends LinkedList<String> implements ResultFactory<Result> {
+
+ private static final long serialVersionUID = 6806221945324235828L;
+
+ public PriorityFieldListResultFactory() {
+ // empty constructor
+ }
+
+ public Result createResult(Document document) {
+
+ for (String field : this) {
+ String value = document.get(field);
+
+ if (value != null) {
+ return new ResultImpl(field, value);
+ }
+
+ }
+
+ return null;
+
+ }
+
+ public Result createResult(String field, String value) {
+ return new ResultImpl(field, value);
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/PropertyDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/PropertyDocumentProcessor.java
new file mode 100644
index 0000000000..20b6635e05
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/PropertyDocumentProcessor.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.lang.reflect.Array;
+
+import org.apache.lucene.document.Field;
+import org.apache.tuscany.sca.assembly.Property;
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DocumentProcessor;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class PropertyDocumentProcessor implements DocumentProcessor {
+
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document doc,
+ String parent) {
+
+ if (object instanceof Property) {
+ Property property = (Property)object;
+ String name = property.getName();
+
+ if (name != null && name.length() > 0) {
+
+ if (doc == null) {
+ doc = documents.get(name);
+ }
+
+ Object value = property.getValue();
+
+ if (value.getClass().isArray()) {
+ int arraySize = Array.getLength(value);
+
+ for (int i = 0; i < arraySize; i++) {
+ Object arrayValue = Array.get(value, i);
+
+ doc.add(new Field(SearchFields.VALUE_FIELD, arrayValue.toString(), Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ }
+
+ } else {
+
+ doc
+ .add(new Field(SearchFields.VALUE_FIELD, value.toString(), Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ }
+
+ return doc == null ? FAKE_DOCUMENT : doc;
+
+ } else {
+ return FAKE_DOCUMENT;
+ }
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+ public Object getDocumentKey(Object object) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ResultImpl.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ResultImpl.java
new file mode 100644
index 0000000000..66e2b73723
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ResultImpl.java
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tuscany.sca.domain.search.Result;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+final public class ResultImpl implements Result {
+
+ private static final long serialVersionUID = 7084570994751217396L;
+
+ private Result container;
+
+ private HashMap<String, Result> contents;
+
+ private String value;
+
+ private String field;
+
+ public ResultImpl() {
+ // empty constructor
+ }
+
+ public ResultImpl(String field, String value) {
+ setValue(value);
+ setField(field);
+
+ }
+
+ public String getField() {
+ return this.field;
+ }
+
+ public void setField(String field) {
+ this.field = field;
+ }
+
+ public Result getContainer() {
+ return this.container;
+ }
+
+ public Map<String, Result> getContents() {
+
+ if (this.contents == null) {
+ return Collections.emptyMap();
+ }
+
+ return Collections.unmodifiableMap(this.contents);
+
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ public void setContainer(Result container) {
+
+ if (container != this.container) {
+
+ if (this.container != null) {
+ this.container.removeContent(this);
+ }
+
+ this.container = container;
+
+ if (container != null) {
+ container.addContent(this);
+ }
+
+ }
+
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+
+ if (obj instanceof Result) {
+ Result artifactResult = (Result)obj;
+
+ if (artifactResult.getValue() == this.value || this.value != null
+ && this.value.equals(artifactResult.getValue())) {
+
+ if (artifactResult.getContainer() == this.container || this.container != null
+ && this.container.equals(artifactResult.getContainer())) {
+
+ Map<String, Result> contents = artifactResult.getContents();
+
+ if (this.contents == null) {
+ return contents.isEmpty();
+
+ } else if (this.contents.equals(contents)) {
+ return true;
+ }
+
+ }
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+ public void addContent(Result artifactResult) {
+ internalGetContents().put(artifactResult.getValue(), artifactResult);
+
+ if (artifactResult.getContainer() != this) {
+ artifactResult.setContainer(this);
+ }
+
+ }
+
+ private HashMap<String, Result> internalGetContents() {
+
+ if (this.contents == null) {
+ this.contents = new HashMap<String, Result>();
+ }
+
+ return this.contents;
+
+ }
+
+ public void removeContent(Result artifactResult) {
+
+ if (this.contents != null) {
+ this.contents.remove(artifactResult);
+
+ artifactResult.setContainer(null);
+
+ if (this.contents.isEmpty()) {
+ this.contents = null;
+ }
+
+ }
+
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 11;
+
+ hash = hash * 31 + (this.container == null ? 7 : this.container.hashCode());
+ hash = hash * 31 + (this.contents == null || this.contents.isEmpty() ? 13 : this.contents.hashCode());
+ hash = hash * 31 + (this.value == null ? 17 : this.value.hashCode());
+
+ return hash;
+
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder("<");
+ Result container = getContainer();
+
+ sb.append(getClass().getName()).append(" name='").append(getValue()).append("' container='")
+ .append(container != null ? container.getValue() : null).append("'>\n");
+
+ Method[] methods = getClass().getMethods();
+
+ for (Method method : methods) {
+ String methodName = method.getName();
+
+ if (method.getReturnType() != void.class) {
+
+ if (method.getParameterTypes().length == 0) {
+
+ if (methodName.startsWith("get") && !"getName".equals(methodName)
+ && !"getContainer".equals(methodName)) {
+
+ try {
+ Object returnedObj = method.invoke(this);
+
+ sb.append('\t');
+
+ if (returnedObj instanceof Map<?, ?>) {
+
+ sb.append("<collection type='")
+ .append(returnedObj.getClass().getGenericInterfaces()[1]).append("'>\n");
+
+ for (Object obj : ((Map<?, ?>)returnedObj).values()) {
+
+ sb.append("\t\t").append(obj.toString()).append("\n");
+
+ }
+
+ sb.append("\t</collection>\n");
+
+ } else if (returnedObj instanceof Collection<?>) {
+
+ sb.append("<collection type='")
+ .append(returnedObj.getClass().getGenericInterfaces()[0]).append("'>\n");
+
+ for (Object obj : (Collection<?>)returnedObj) {
+
+ sb.append("\t\t").append(obj.toString()).append("\n");
+
+ }
+
+ sb.append("\t</collection>\n");
+
+ } else if (returnedObj.getClass().isArray()) {
+
+ sb.append("<array type='").append(returnedObj.getClass().getComponentType())
+ .append("'>\n");
+
+ int length = Array.getLength(returnedObj);
+
+ for (int i = 0; i < length; i++) {
+
+ sb.append("\t\t").append(Array.get(returnedObj, i).toString()).append("\n");
+
+ }
+
+ sb.append("\t</array>\n");
+
+ } else {
+
+ sb.append('\t').append(returnedObj).append('\n');
+
+ }
+
+ } catch (Throwable e) {
+ // ignore exceptions and don't print the object
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ sb.append("</").append(getClass().getName()).append(">");
+
+ return sb.toString();
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ResultProcessorList.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ResultProcessorList.java
new file mode 100644
index 0000000000..27c192cbee
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ResultProcessorList.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+
+import org.apache.lucene.document.Document;
+import org.apache.tuscany.sca.domain.search.Result;
+import org.apache.tuscany.sca.domain.search.ResultFactory;
+import org.apache.tuscany.sca.domain.search.ResultProcessor;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class ResultProcessorList extends LinkedList<ResultProcessor> implements ResultProcessor {
+
+
+ private static final long serialVersionUID = 7147307292452694895L;
+
+ private HashMap<String, ResultHashMap> resultRoots = new HashMap<String, ResultHashMap>();
+
+ private ResultFactory<? extends Result> resultFactory;
+
+ public ResultProcessorList(ResultFactory<? extends Result> resultFactory) {
+ this.resultFactory = resultFactory;
+ }
+
+ public Result process(Document document, Result result) {
+
+ if (result == null) {
+ result = this.resultFactory.createResult(document);
+
+ if (result == null) {
+ return null;
+ }
+
+ }
+
+ ResultHashMap resultHashMap;
+
+ String parent = document.get(SearchFields.PARENT_FIELD);
+
+ if (parent == null) {
+ resultHashMap = new ResultHashMap(result);
+ resultRoots.put(result.getValue(), resultHashMap);
+
+ } else {
+
+ ParentField parentField = new ParentField(parent);
+ HashMap<String, ResultHashMap> current = this.resultRoots;
+ // Result currentResult = null;
+ int elementsCount = parentField.getElementsCount();
+
+ for (int i = 0; i < elementsCount; i++) {
+ String actualName = parentField.getElementName(i);
+ String type = parentField.getElementType(i);
+
+ if (actualName.length() > 0) {
+ ResultHashMap actualResultHashMap = current.get(actualName);
+
+ if (actualResultHashMap == null) {
+ ResultHashMap aux = new ResultHashMap(type, parentField.getElementName(i));
+
+ current.put(aux.result.getValue(), aux);
+ // if (current.put(aux.result.getValue(), aux) == null
+ // && currentResult != null) {
+ // currentResult.addContent(aux.result);
+ // }
+
+ current = aux;
+ // currentResult = aux.result;
+
+ } else {
+ current = actualResultHashMap;
+ // currentResult = actualResultHashMap.result;
+
+ }
+
+ }
+
+ }
+
+ resultHashMap = current.get(result.getValue());
+
+ if (resultHashMap == null) {
+ resultHashMap = new ResultHashMap(result);
+ current.put(result.getValue(), resultHashMap);
+
+ // if (currentResult != null) {
+ // currentResult.addContent(result);
+ // }
+
+ }
+
+ }
+
+ for (ResultProcessor processor : this) {
+ result = processor.process(document, result);
+ }
+
+ resultHashMap.result = result;
+
+ return result;
+
+ }
+
+ private static void addContentsToResult(ResultHashMap resultHashMap) {
+
+ for (ResultHashMap actual : resultHashMap.values()) {
+ addContentsToResult(actual);
+
+ resultHashMap.result.addContent(actual.result);
+
+ }
+
+ }
+
+ public Result[] createResultRoots() {
+ int size = this.resultRoots.size();
+
+ if (size == 0) {
+ return new Result[0];
+ }
+
+ Result[] res = new Result[size];
+
+ int i = 0;
+ for (ResultHashMap resultHashMap : this.resultRoots.values()) {
+
+ addContentsToResult(resultHashMap);
+ res[i++] = resultHashMap.result;
+
+ }
+
+ this.resultRoots.clear();
+
+ return res;
+
+ }
+
+ private Result createResult(String field, String value) {
+ Result result = this.resultFactory.createResult(field, value);
+
+ if (result != null) {
+ return result;
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+ private class ResultHashMap extends HashMap<String, ResultHashMap> {
+
+ private static final long serialVersionUID = 7982561264440904411L;
+
+ Result result;
+
+ ResultHashMap(String type, String name) {
+ this(createResult(type, name));
+ }
+
+ ResultHashMap(Result result) {
+ this.result = result;
+ }
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/SearchFields.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/SearchFields.java
new file mode 100644
index 0000000000..abfaa8c466
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/SearchFields.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public interface SearchFields {
+
+ final public static String ARTIFACT_FIELD = "artifact";
+
+ final public static String COMPONENT_TYPE_FIELD = "componenttype";
+
+ final public static String REFERENCE_FIELD = "reference";
+
+ final public static String COMPOSITE_FIELD = "composite";
+
+ final public static String SERVICE_FIELD = "service";
+
+ final public static String BINDING_FIELD = "binding";
+
+ final public static String CONTRIBUTION_FIELD = "contribution";
+
+ final public static String COMPONENT_FIELD = "component";
+
+ final public static String TYPE_FIELD = "type";
+
+ final public static String PARENT_FIELD = "parent";
+
+ final public static String IMPLEMENTS_FIELD = "implements";
+
+ final public static String SERVICE_NAME_FIELD = "servicename";
+
+ final public static String SERVICE_INTERFACE_FIELD = "serviceinterface";
+
+ final public static String SERVICE_INTERFACE_CALLBACK_FIELD = "serviceinterfacecallback";
+
+ final public static String REFERENCE_NAME_FIELD = "referencename";
+
+ final public static String REFERENCE_INTERFACE_FIELD = "referenceinterface";
+
+ final public static String REFERENCE_INTERFACE_CALLBACK_FIELD = "referenceinterfacecallback";
+
+ final public static String IMPORTEDBY_FIELD = "importedby";
+
+ final public static String EXPORTEDBY_FIELD = "exportedby";
+
+ final public static String INCLUDEDBY_FIELD = "includedby";
+
+ final public static String PROPERTY_KEY_FIELD = "propertykey";
+
+ final public static String VALUE_FIELD = "propertyvalue";
+
+ final public static String FILE_CONTENT_FIELD = "filecontent";
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/SystemFileContent.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/SystemFileContent.java
new file mode 100644
index 0000000000..3d75c2b86e
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/SystemFileContent.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class SystemFileContent implements FileContent {
+
+ private static final long serialVersionUID = -8337926886777467728L;
+
+ final boolean leaf;
+
+ final private File file;
+
+ public SystemFileContent(File file) {
+ this.leaf = !file.isDirectory();
+ this.file = file;
+
+ }
+
+ public File getFile() {
+ return this.file;
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return new FileInputStream(this.file);
+ }
+
+ public FileContent[] getChildren() {
+ File[] files = this.file.listFiles();
+ FileContent[] ret = new FileContent[files.length];
+
+ for (int i = 0; i < files.length; i++) {
+ ret[i] = new SystemFileContent(files[i]);
+ }
+
+ return ret;
+
+ }
+
+ public boolean isLeaf() {
+ return this.leaf;
+ }
+
+ public String getName() {
+ return this.file.getName();
+ }
+
+ public String getPath() {
+ return this.file.getPath();
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/WrappedFileContent.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/WrappedFileContent.java
new file mode 100644
index 0000000000..78434d4c0d
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/WrappedFileContent.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.URL;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class WrappedFileContent implements FileContent {
+
+ final private FileContent fileContent;
+
+ public WrappedFileContent(URL url) throws IOException {
+ String protocol = url.getProtocol();
+
+ if (protocol.equals("jar")) {
+ JarURLConnection jarConn = (JarURLConnection)url.openConnection();
+ String file = url.getFile();
+ file = file.substring(file.lastIndexOf('!') + 1);
+
+ this.fileContent = ZipFileContent.createZipFileContent(jarConn.getJarFile(), file);
+
+ } else if (protocol.equals("file")) {
+ this.fileContent = new SystemFileContent(new File(url.getFile()));
+
+ } else {
+ this.fileContent = new DefaultFileContent(url);
+ }
+
+ }
+
+ public FileContent[] getChildren() {
+ return this.fileContent.getChildren();
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return this.fileContent.getInputStream();
+ }
+
+ public String getName() {
+ return this.fileContent.getName();
+ }
+
+ public String getPath() {
+ return this.fileContent.getPath();
+ }
+
+ public boolean isLeaf() {
+ return this.fileContent.isLeaf();
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ZipDocumentProcessor.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ZipDocumentProcessor.java
new file mode 100644
index 0000000000..2337c40fc1
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ZipDocumentProcessor.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.zip.ZipFile;
+
+import org.apache.lucene.document.Field;
+import org.apache.tuscany.sca.domain.search.DocumentMap;
+import org.apache.tuscany.sca.domain.search.DocumentProcessor;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class ZipDocumentProcessor implements DocumentProcessor {
+
+ public Object getDocumentKey(Object object) {
+
+ if (object instanceof File) {
+ File file = (File)object;
+ String path = file.getPath();
+
+ if (path != null && path.length() == 0) {
+ return null;
+ }
+
+ return path;
+
+ }
+
+ throw new IllegalArgumentException();
+
+ }
+
+ public Document process(DocumentProcessor parentProcessor,
+ DocumentMap documents,
+ Object object,
+ Document document,
+ String parent) {
+
+ if (object instanceof SystemFileContent) {
+ SystemFileContent file = (SystemFileContent)object;
+
+ try {
+ ZipFile zip = new ZipFile(file.getFile());
+
+ if (document == null) {
+ document = documents.get(file.getPath());
+ }
+
+ parent +=
+ DomainPathAnalyzer.PATH_SEPARATOR + SearchFields.ARTIFACT_FIELD
+ + DomainPathAnalyzer.TYPE_SEPARATOR
+ + "jar:file:"
+ + file.getPath()
+ + DomainPathAnalyzer.ARCHIVE_SEPARATOR
+ + '/'
+ + file.getName()
+ + DomainPathAnalyzer.URI_SEPARATOR
+ + file.getName();
+
+ document.add(new Field(SearchFields.ARTIFACT_FIELD, file.getName(), Field.Store.YES,
+ Field.Index.ANALYZED));
+
+ ZipFileContent[] zipFiles = ZipFileContent.createZipFileContent(zip);
+
+ for (ZipFileContent zipFile : zipFiles) {
+
+ parentProcessor.process(parentProcessor, documents, zipFile, document, parent);
+
+ }
+
+ return document;
+
+ } catch (IOException e) {
+ // ignore file
+ }
+
+ }
+
+ return null;
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ZipFileContent.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ZipFileContent.java
new file mode 100644
index 0000000000..15f9bb6feb
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/main/java/org/apache/tuscany/sca/domain/search/impl/ZipFileContent.java
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class ZipFileContent implements FileContent {
+
+ final private ZipFile file;
+
+ final private ZipEntry entry;
+
+ private FileContent[] children;
+
+ private ZipFileContent(ZipFile file, ZipEntry entry) {
+ this.file = file;
+ this.entry = entry;
+
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return this.file.getInputStream(this.entry);
+ }
+
+ public String getPath() {
+ return this.file.getName() + DomainPathAnalyzer.ARCHIVE_SEPARATOR + '/' + this.entry.getName();
+ }
+
+ public FileContent[] getChildren() {
+ return this.children;
+ }
+
+ public String getName() {
+ return this.entry.getName();
+ // int lastSlashIndex = name.lastIndexOf('/');
+ //
+ // if (lastSlashIndex == -1) {
+ // return name;
+ // }
+ //
+ // if (lastSlashIndex == name.length() - 1 && name.length() > 1) {
+ // lastSlashIndex = name.lastIndexOf('/', name.length() - 2);
+ //
+ // if (lastSlashIndex == -1) {
+ // return name.substring(0, name.length() - 1);
+ // }
+ //
+ // return name.substring(lastSlashIndex + 1, name.length() - 1);
+ //
+ // }
+ //
+ // return name.substring(lastSlashIndex + 1);
+
+ }
+
+ public boolean isLeaf() {
+ return !this.entry.isDirectory();
+ }
+
+ public static ZipFileContent[] createZipFileContent(ZipFile file) {
+ Enumeration<? extends ZipEntry> entries = file.entries();
+
+ if (!entries.hasMoreElements()) {
+ return null;
+ }
+
+ HashMap<String, ZipMap> roots = new HashMap<String, ZipMap>();
+
+ do {
+ ZipEntry entry = entries.nextElement();
+ String name = entry.getName();
+
+ if (name.length() > 0) {
+
+ String[] path = name.split("/");
+
+ ZipMap current = roots.get(path[0]);
+
+ if (current == null) {
+ current = new ZipMap();
+ roots.put(path[0], current);
+
+ if (path.length == 1) {
+ current.setEntry(file, entry);
+ continue;
+
+ }
+
+ }
+
+ for (int i = 1; i < path.length - 1; i++) {
+ ZipMap actual = current.get(path[i]);
+
+ if (actual == null) {
+ actual = new ZipMap();
+ current.put(path[i], actual);
+
+ }
+
+ current = actual;
+
+ }
+
+ ZipMap entryMap = current.get(path[path.length - 1]);
+
+ if (entryMap == null) {
+ entryMap = new ZipMap();
+ current.put(path[path.length - 1], entryMap);
+
+ }
+
+ entryMap.setEntry(file, entry);
+
+ }
+
+ } while (entries.hasMoreElements());
+
+ for (ZipMap map : roots.values()) {
+ createZipFileContentChildren(map);
+ }
+
+ ZipFileContent[] ret = new ZipFileContent[roots.size()];
+ int i = 0;
+
+ for (ZipMap rootMap : roots.values()) {
+ ret[i++] = rootMap.zipContent;
+ }
+
+ return ret;
+
+ }
+
+ public static ZipFileContent createZipFileContent(ZipFile file, String filePath) {
+
+ Enumeration<? extends ZipEntry> entries = file.entries();
+
+ if (!entries.hasMoreElements()) {
+ return null;
+ }
+
+ int beginIndex;
+ int endIndex;
+
+ if (filePath.charAt(0) == '/') {
+ beginIndex = 1;
+
+ } else {
+ beginIndex = 0;
+ }
+
+ ZipMap root = new ZipMap();
+
+ if (filePath.length() > 1 && filePath.charAt(filePath.length() - 1) == '/') {
+ endIndex = filePath.length() - 1;
+
+ } else {
+ endIndex = filePath.length();
+ }
+
+ filePath = filePath.substring(beginIndex, endIndex);
+ // HashMap<String, ZipMap> roots = new HashMap<String, ZipMap>();
+
+ do {
+ ZipEntry entry = entries.nextElement();
+ String name = entry.getName();
+
+ if (name.length() > 0) {
+
+ if (name.charAt(name.length() - 1) == '/') {
+ endIndex = 1;
+
+ } else {
+ endIndex = 0;
+ }
+
+ if (name.length() - endIndex == filePath.length()) {
+ root.setEntry(file, entry);
+
+ } else if (filePath.length() == 0 || (name.startsWith(filePath) && name.charAt(filePath.length()) == '/')) {
+
+ name = name.substring(filePath.length());
+ String[] path = name.split("/");
+
+ ZipMap current = root;
+
+ // if (current == null) {
+ // current = new ZipMap();
+ // roots.put(path[0], current);
+ //
+ // if (path.length == 1) {
+ // current.setEntry(file, entry);
+ // continue;
+ //
+ // }
+ //
+ // }
+
+ if (path.length > 0) {
+
+ int i;
+
+ if (path[0].length() == 0) {
+ i = 1;
+
+ } else {
+ i = 0;
+ }
+
+ for (; i < path.length - 1; i++) {
+ ZipMap actual = current.get(path[i]);
+
+ if (actual == null) {
+ actual = new ZipMap();
+ current.put(path[i], actual);
+
+ }
+
+ current = actual;
+
+ }
+
+ ZipMap entryMap = current.get(path[path.length - 1]);
+
+ if (entryMap == null) {
+ entryMap = new ZipMap();
+ current.put(path[path.length - 1], entryMap);
+
+ }
+
+ entryMap.setEntry(file, entry);
+
+ }
+
+ }
+
+ }
+
+ } while (entries.hasMoreElements());
+
+ createZipFileContentChildren(root);
+
+ return root.zipContent;
+
+ }
+
+ private static void createZipFileContentChildren(ZipMap map) {
+ ZipFileContent[] children = new ZipFileContent[map.size()];
+ int i = 0;
+
+ for (ZipMap childMap : map.values()) {
+
+ if (childMap.zipContent == null) {
+ throw new RuntimeException("could not load zip file hierarchy for file: " + map.zipContent.file);
+ }
+
+ children[i++] = childMap.zipContent;
+
+ createZipFileContentChildren(childMap);
+
+ }
+
+ map.zipContent.children = children;
+
+ }
+
+ @Override
+ public String toString() {
+ return this.file.getName() + '/' + this.entry.getName();
+ }
+
+ private static class ZipMap extends HashMap<String, ZipMap> {
+
+ private static final long serialVersionUID = 6514645087432837480L;
+
+ ZipFileContent zipContent;
+
+ void setEntry(ZipFile zipFile, ZipEntry entry) {
+ this.zipContent = new ZipFileContent(zipFile, entry);
+ }
+
+ ZipFileContent[] getChildren() {
+
+ ZipFileContent ret[] = new ZipFileContent[this.size()];
+ int i = 0;
+
+ for (ZipMap actual : this.values()) {
+ ret[i++] = actual.zipContent;
+ }
+
+ return ret;
+
+ }
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/test/java/org/apache/tuscany/sca/domain/search/impl/DomainPathAnalyzerTestCase.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/test/java/org/apache/tuscany/sca/domain/search/impl/DomainPathAnalyzerTestCase.java
new file mode 100644
index 0000000000..74c18beb52
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/test/java/org/apache/tuscany/sca/domain/search/impl/DomainPathAnalyzerTestCase.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.Tokenizer;
+
+public class DomainPathAnalyzerTestCase extends TestCase {
+
+ private Token reusableToken = new Token();
+
+ public void test() throws IOException {
+
+ Tokenizer tokenizer = new DomainPathAnalyzer.DomainPathTokenizer(new StringReader(
+ Character.toString(DomainPathAnalyzer.PATH_START) + SearchFields.CONTRIBUTION_FIELD + DomainPathAnalyzer.TYPE_SEPARATOR + "123tuscany" + DomainPathAnalyzer.PATH_START + DomainPathAnalyzer.TYPE_SEPARATOR + "SCA" +
+ DomainPathAnalyzer.PATH_SEPARATOR + DomainPathAnalyzer.TYPE_SEPARATOR + "TuscanySCA" + DomainPathAnalyzer.TYPE_SEPARATOR + "321" + DomainPathAnalyzer.URI_SEPARATOR + "123"));
+
+ assertNextToken(Character.toString(DomainPathAnalyzer.PATH_START), tokenizer);
+ assertNextToken("123", tokenizer);
+ assertNextToken("tuscany", tokenizer);
+ assertNextToken(Character.toString(DomainPathAnalyzer.PATH_START), tokenizer);
+ assertNextToken("sca", tokenizer);
+ assertNextToken(Character.toString(DomainPathAnalyzer.PATH_SEPARATOR), tokenizer);
+ assertNextToken("tuscany", tokenizer);
+ assertNextToken("sca", tokenizer);
+ assertNextToken("123", tokenizer);
+
+ }
+
+ private void assertNextToken(String expected, Tokenizer tokenizer)
+ throws IOException {
+ Token token = tokenizer.next(reusableToken);
+
+ assertNotNull(token);
+ assertEquals(expected, token.term());
+
+ }
+
+}
diff --git a/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/test/java/org/apache/tuscany/sca/domain/search/impl/NamingTokenizerTestCase.java b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/test/java/org/apache/tuscany/sca/domain/search/impl/NamingTokenizerTestCase.java
new file mode 100644
index 0000000000..5070202d88
--- /dev/null
+++ b/sca-java-1.x/tags/1.6-TUSCANY-3909/domain-search/src/test/java/org/apache/tuscany/sca/domain/search/impl/NamingTokenizerTestCase.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.domain.search.impl;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.Tokenizer;
+
+public class NamingTokenizerTestCase extends TestCase {
+
+ private Token reusableToken = new Token();
+
+ public void testDigits() throws IOException {
+ NamingTokenizer tokenizer = new NamingTokenizer(new StringReader(
+ "123tuscany"));
+
+ assertNextToken("123", tokenizer);
+ assertNextToken("tuscany", tokenizer);
+
+ tokenizer.reset(new StringReader("tuscany123"));
+
+ assertNextToken("tuscany", tokenizer);
+ assertNextToken("123", tokenizer);
+
+ tokenizer.reset(new StringReader("TUSCANY123"));
+
+ assertNextToken("tuscany", tokenizer);
+ assertNextToken("123", tokenizer);
+
+ tokenizer.reset(new StringReader("123TUSCANY"));
+
+ assertNextToken("123", tokenizer);
+ assertNextToken("tuscany", tokenizer);
+
+ tokenizer.reset(new StringReader("tuscany.123"));
+
+ assertNextToken("tuscany", tokenizer);
+ assertNextToken("123", tokenizer);
+
+ tokenizer.reset(new StringReader("123.tuscany"));
+
+ assertNextToken("123", tokenizer);
+ assertNextToken("tuscany", tokenizer);
+
+ }
+
+ public void testUppercasedTokens() throws IOException {
+ NamingTokenizer tokenizer = new NamingTokenizer(new StringReader(
+ "SCATuscany"));
+
+ assertNextToken("sca", tokenizer);
+ assertNextToken("tuscany", tokenizer);
+
+ tokenizer.reset(new StringReader("TuscanySCA"));
+
+ assertNextToken("tuscany", tokenizer);
+ assertNextToken("sca", tokenizer);
+
+ tokenizer.reset(new StringReader("Tuscany.SCA"));
+
+ assertNextToken("tuscany", tokenizer);
+ assertNextToken("sca", tokenizer);
+
+ tokenizer.reset(new StringReader("SCA.Tuscany"));
+
+ assertNextToken("sca", tokenizer);
+ assertNextToken("tuscany", tokenizer);
+
+ tokenizer.reset(new StringReader("SCA"));
+
+ assertNextToken("sca", tokenizer);
+
+ }
+
+ public void testRegularTokens() throws IOException {
+ NamingTokenizer tokenizer = new NamingTokenizer(new StringReader(
+ "scaTuscany"));
+
+ assertNextToken("sca", tokenizer);
+ assertNextToken("tuscany", tokenizer);
+
+ tokenizer.reset(new StringReader("ScaTuscany"));
+
+ assertNextToken("sca", tokenizer);
+ assertNextToken("tuscany", tokenizer);
+
+ tokenizer.reset(new StringReader("ScaTuscanY"));
+
+ assertNextToken("sca", tokenizer);
+ assertNextToken("tuscan", tokenizer);
+ assertNextToken("y", tokenizer);
+
+ }
+
+ public void testSingleCharTokens() throws IOException {
+
+ NamingTokenizer tokenizer = new NamingTokenizer(new StringReader("1"));
+
+ assertNextToken("1", tokenizer);
+
+ tokenizer.reset(new StringReader("a"));
+
+ assertNextToken("a", tokenizer);
+
+ tokenizer.reset(new StringReader("A"));
+
+ assertNextToken("a", tokenizer);
+
+ }
+
+ public void testNullTokens() throws IOException {
+ NamingTokenizer tokenizer = new NamingTokenizer(new StringReader("_"));
+ assertNull(tokenizer.next(this.reusableToken));
+
+ tokenizer.reset(new StringReader("."));
+ assertNull(tokenizer.next(this.reusableToken));
+
+ tokenizer.reset(new StringReader(" "));
+ assertNull(tokenizer.next(this.reusableToken));
+
+ tokenizer.reset(new StringReader(""));
+ assertNull(tokenizer.next(this.reusableToken));
+
+ tokenizer.reset(new StringReader(" )(%*%"));
+ assertNull(tokenizer.next(this.reusableToken));
+
+ }
+
+ private void assertNextToken(String expected, Tokenizer tokenizer)
+ throws IOException {
+ Token token = tokenizer.next(reusableToken);
+
+ assertNotNull(token);
+ assertEquals(expected, token.term());
+
+ }
+
+}