/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.core.index; import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.container.Container; import org.teiid.designer.core.container.DuplicateResourceException; import org.teiid.designer.core.metadata.runtime.RuntimeAdapter; import org.teiid.designer.core.util.ModelObjectCollector; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.core.workspace.ModelWorkspace; import org.teiid.designer.core.workspace.ModelWorkspaceException; import org.teiid.designer.core.workspace.WorkspaceResourceFinderUtil; /** * An <code>ModelIndexer</code> indexes ONE document at each time. It adds the document names and the words references to an * IIndex. Each IIndexer can index certain types of document, and should not index the other files. * * @since 8.0 */ public class ModelIndexer implements ResourceIndexer { /** If true the contents of the index files will be printed to System.out */ public static boolean PRINT_INDEX_CONTENTS = false; private static final String[] FILE_TYPES = new String[] {"model"}; //$NON-NLS-1$ private static String INDEX_TYPES = ModelerCore.Util.getString("ModelIndexer.Metadata_Indexes_1"); //$NON-NLS-1$ // ================================================================================== // I N T E R F A C E M E T H O D S // ================================================================================== public ModelIndexer() { } private IndexingContext createQueryContext() { Collection resources; Container container; try { // assume model container...modler metadata is for workspace container = ModelerCore.getModelContainer(); ModelWorkspace workspace = ModelerCore.getModelWorkspace(); if (workspace.isOpen()) { resources = Arrays.asList(workspace.getEmfResources()); } else { resources = container.getResources(); } IndexingContext context = new IndexingContext(); context.setResourcesInContext(resources); return context; } catch (CoreException e) { ModelerCore.Util.log(e); } return null; } /* (non-Javadoc) * @See org.teiid.designer.core.index.ResourceIndexer#getIndexType() */ @Override public String getIndexType() { return INDEX_TYPES; } /* (non-Javadoc) * @see org.teiid.core.index.IIndexer#getFileTypes() */ @Override public String[] getFileTypes() { return FILE_TYPES; } /* (non-Javadoc) * @see org.teiid.core.index.IIndexer#setFileTypes(java.lang.String[]) */ @Override public void setFileTypes( final String[] fileTypes ) { } /* (non-Javadoc) * @see org.teiid.designer.core.index.IIndexer#shouldIndex(org.teiid.designer.core.index.IDocument) */ @Override public boolean shouldIndex( final IDocument document ) { if (document instanceof ModelDocument) { return true; } return false; } /** * Indexes the given emf resource, adding the resource name and the word references to this resource to the given * <code>ModelIndex</code>.The caller should use <code>shouldIndex()</code> first to determine whether this indexer handles * the given type of EmfResource, and only call this method if so. */ @Override public final void index( final IDocument document, final IIndexerOutput output ) { CoreArgCheck.isNotNull(document); CoreArgCheck.isNotNull(output); if (!this.shouldIndex(document)) { return; } // ------------------------------------ // Defect 22774 - (BML 10/3/06) added ability to set the initial index array size prior to creating the index words. // This should improve performance a little for little models and a little more for large models with many indexes. // ------------------------------------ int initialIndexSize = 10; List eObjects = Collections.EMPTY_LIST; String modelPath = null; if (document instanceof ModelDocument) { // Get the indexName from the given ModelDocument final ModelDocument modelDocument = (ModelDocument)document; modelPath = modelDocument.getIResource().getFullPath().toString(); // get the emf resource Resource emfResource = modelDocument.getResource(); final ModelObjectCollector moc = new ModelObjectCollector(emfResource); eObjects = moc.getEObjects(); initialIndexSize += eObjects.size(); } // list of words to be added to the index List indexWords = new ArrayList(initialIndexSize); // Add any WordEntry instances for the resource being indexed this.addResourceWordEntries(document, indexWords); // ModelerCore.Util.log(IStatus.INFO, " -------------- ModelIndexer.index() START ----------------------"); // ModelerCore.Util.log(IStatus.INFO, " >> Indexing emfResource = " + document.getName()); // ModelerCore.Util.log(IStatus.INFO, " >> # EObjects = " + eObjects.size()); if (document instanceof ModelDocument) { IndexingContext context = createQueryContext(); for (final Iterator iter = eObjects.iterator(); iter.hasNext();) { final EObject eObject = (EObject)iter.next(); // Add the appropriate word entries for the given EObject this.addIndexWord(eObject, context, modelPath, indexWords); } } // Preprocess the WordEntry list prior to creating the index file this.sortWordEntries(indexWords); // Add the entries to the index file output.addDocument(document); addEntries(output, indexWords); if (PRINT_INDEX_CONTENTS && !(this instanceof ModelSearchIndexer)) { printWordEntryList(indexWords, System.out); } // free up memory, clear the index words indexWords = null; // ModelerCore.Util.log(IStatus.INFO, " -------Finished Indexing END -----------------------\n"); } /* (non-Javadoc) * @See org.teiid.designer.core.index.ResourceIndexer#indexResource(org.eclipse.core.runtime.IPath, boolean, boolean) */ @Override public void indexResource( final IResource resource, final boolean reuseExistingFile, final boolean addResource ) throws ModelerCoreException { CoreArgCheck.isNotNull(resource); ModelWorkspace workspace = ModelerCore.getModelWorkspace(); ModelResource mResource = workspace.findModelResource(resource); // Find the EMF resource for it ... Resource emfResource = null; if (mResource != null) { try { emfResource = mResource.getEmfResource(); // will cause opening if not already open; may be problesm opening } catch (ModelWorkspaceException err) { final Throwable wrapped = err.getException(); if (wrapped instanceof DuplicateResourceException) { // Don't do anything about this } else { throw err; } } } // relative path in workspace IPath path = resource.getFullPath(); try { String fileName = this.getIndexFileName(path); // runtime index path String indexFilePath = IndexUtil.getIndexFilePath(IndexUtil.INDEX_PATH, fileName); if (ModelerCore.DEBUG || ModelerCore.DEBUG_PROJECT_BUILDER) { final Object[] params = new Object[] {fileName, path}; final String msg = ModelerCore.Util.getString("IndexUtil.DEBUG.Creating_index_file_0_for_resource_1_1", params); //$NON-NLS-1$ ModelerCore.Util.log(IStatus.INFO, msg); } IDocument document = null; if (emfResource != null) { if (mResource != null) { // model document document = new ModelDocumentImpl(path.toFile(), resource, emfResource); } else { // file document document = new ResourceDocumentImpl(path.toFile(), resource); } } if (document != null) { // create the index IIndex runtimeIndex = IndexUtil.getNewIndexFile(fileName, indexFilePath, resource.getName()); if (addResource) { runtimeIndex.add(document, this); } else { runtimeIndex.remove(document.getName()); } runtimeIndex.save(); } // if this is a model resource, mark it as indexed if (mResource != null) { this.setIndexType(mResource); } } catch (Exception e) { IStatus status = new Status(IStatus.ERROR, ModelerCore.PLUGIN_ID, IStatus.OK, ModelerCore.Util.getString("ModelBuilder.IO_Error_trying_to_index_an_EmfResource_2"), e); //$NON-NLS-1$ throw new ModelerCoreException(status); } } /* (non-Javadoc) * @See org.teiid.designer.core.index.ResourceIndexer#indexResource(org.eclipse.core.resources.IResource, boolean, boolean) */ @Override public void indexResource( IPath path, boolean reuseExistingFile, boolean addResource ) throws ModelerCoreException { CoreArgCheck.isNotNull(path); IResource resource = WorkspaceResourceFinderUtil.findIResourceByPath(path); indexResource(resource, reuseExistingFile, addResource); } // ================================================================================== // P R O T E C T E D M E T H O D S // ================================================================================== /** * Set the indexType on the modelResource, each indexer is responsible for setting the appropriate Type. * * @param resource The modelResource whose index type is set */ protected void setIndexType( final ModelResource resource ) { CoreArgCheck.isNotNull(resource); if (resource.getIndexType() == ModelResource.NOT_INDEXED) { resource.setIndexType(ModelResource.METADATA_INDEXED); } else if (resource.getIndexType() == ModelResource.SEARCH_INDEXED) { resource.setIndexType(ModelResource.INDEXED); } } /** * Get the files name that would contain index information for the given resource. * * @param path The path to the resource whose index files names are returned * @return The index file name for this resource */ protected String getIndexFileName( final IPath path ) { return IndexUtil.getIndexFileName(path.toString(), IndexConstants.INDEX_EXT); } /** * Create the {@link WordEntry} instance(s) to be used as the index file record(s) for * this EObject instance. The word entries are added to the list provided by the calling method. * * @param EObject * @param modelPath path to the model within the workspace * @param wordEntries the list to which WordEntry instances are added * @return */ protected void addIndexWord( final EObject eObject, IndexingContext context, final String modelPath, final List wordEntries ) { RuntimeAdapter.addIndexWord(eObject, context, modelPath, wordEntries, true); } /** * Sort the list of WordEntry instances prior to adding the entries to the IIndexerOutput. * * @param wordEntries the list to be sorted */ protected void sortWordEntries( final List wordEntries ) { // sort the lists alphabetically (for better query performance) using a comparator WordEntryComparator wComparator = new WordEntryComparator(); Collections.sort(wordEntries, wComparator); } /** * Add {@link WordEntry} instance(s) for the resource that is being indexed. * * @param document * @param wordEntries */ protected void addResourceWordEntries( final IDocument document, final List wordEntries ) { // do nothing by default. } // ================================================================================== // P R I V A T E M E T H O D S // ================================================================================== /** * Add word entries to indexoutput. */ private void addEntries( final IIndexerOutput output, final List entries ) { Iterator entryIter = entries.iterator(); while (entryIter.hasNext()) { WordEntry entry = (WordEntry)entryIter.next(); output.addRef(entry.getWord()); } } private void printWordEntryList( final List wordEntries, final PrintStream stream ) { for (Iterator iter = wordEntries.iterator(); iter.hasNext();) { WordEntry entry = (WordEntry)iter.next(); stream.println(entry.toString()); } } }