/** * */ package er.indexing; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.Enumeration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSBundle; import com.webobjects.foundation.NSDictionary; import com.webobjects.foundation.NSForwardException; import com.webobjects.foundation.NSMutableDictionary; import com.webobjects.foundation.NSNotification; import com.webobjects.foundation.NSPropertyListSerialization; import com.webobjects.foundation.NSSelector; import com.webobjects.foundation._NSUtilities; import er.extensions.ERXExtensions; import er.extensions.ERXFrameworkPrincipal; import er.extensions.appserver.ERXApplication; import er.extensions.foundation.ERXFileNotificationCenter; import er.extensions.foundation.ERXMutableDictionary; import er.extensions.foundation.ERXPatcher; import er.extensions.foundation.ERXProperties; import er.extensions.foundation.ERXSelectorUtilities; import er.extensions.foundation.ERXStringUtilities; public class ERIndexing extends ERXFrameworkPrincipal { private static final Logger log = LoggerFactory.getLogger(ERIndexing.class); // Master dictionary of indices NSMutableDictionary indices = ERXMutableDictionary.synchronizedDictionary(); public final static Class REQUIRES[] = new Class[] {ERXExtensions.class}; static { setUpFrameworkPrincipalClass (ERIndexing.class); } private File _indexRoot; private File indexRoot() { if(_indexRoot == null) { String name = ERXProperties.stringForKeyWithDefault("er.indexing.ERIndexModel.rootDirectory", "/tmp"); _indexRoot = new File(name); } return _indexRoot; } /** * Searches all bundles for *.indexModel resources files and dserializes the index definitions and adds * the index definitions to the master dictionary of application indices */ public void loadIndexDefinitions() { // Check every bundle (app and frameworks) for (Enumeration bundles = NSBundle._allBundlesReally().objectEnumerator(); bundles.hasMoreElements();) { NSBundle bundle = (NSBundle) bundles.nextElement(); // Get list of all files with extension indexModel NSArray<String> files = bundle.resourcePathsForResources("indexModel", null); for (String file : files) { URL url = bundle.pathURLForResourcePath(file); // Get the name of the indexModel file withut the directory path and without the file extension String name = url.toString().replaceAll(".*?/(\\w+)\\.indexModel$", "$1"); if(url != null) { // If in development mode, observe the indexModel file for changes // so that the index can be recreated if(ERXApplication.isDevelopmentModeSafe()) { NSSelector selector = ERXSelectorUtilities.notificationSelector("fileDidChange"); ERXFileNotificationCenter.defaultCenter().addObserver(this, selector, url.getFile()); } // Get contents of indexModel file String string = ERXStringUtilities.stringFromResource(name, "indexModel", bundle); // Convert file contents into nested NSDictionary NSDictionary dict = (NSDictionary)NSPropertyListSerialization.propertyListFromString(string); // Create the lucene index with name and dictionary definition addIndex(name, dict); log.info("Added index: {}", name); } } } } public void fileDidChange(NSNotification n) throws MalformedURLException { File file = (File) n.object(); loadModel(file.toURI().toURL()); } private void loadModel(URL url) { NSDictionary def = (NSDictionary) NSPropertyListSerialization.propertyListWithPathURL(url); for (Enumeration keys = def.allKeys().objectEnumerator(); keys.hasMoreElements();) { String key = (String) keys.nextElement(); NSDictionary indexDef = (NSDictionary) def.objectForKey(key); addIndex(key, indexDef); } } /** * @param key the name of the index * @param index the indexer instance having the name of the index and the index definition from the indexModel file */ protected void addIndex(String key, ERIndex index) { indices.setObjectForKey(index, key); } /** * @param key the name of the index * @param indexDef the dictionary containing the index definition (usually deserialized from the indexModel file) */ private void addIndex(String key, NSDictionary indexDef) { // Classname for the class that will create the lucene index String className = (String) indexDef.objectForKey("index"); NSMutableDictionary dict = indexDef.mutableClone(); // If index store not defined, default to index named the dsame as the indexModel file in the indexRoot directory if(!dict.containsKey("store")) { try { dict.setObjectForKey(new File(indexRoot(), key).toURI().toURL().toString(), "store"); } catch (MalformedURLException e) { throw NSForwardException._runtimeExceptionForThrowable(e); } } // Create the class that will create the index. Defaults to ERAutoIndex ERIndex index; if (className != null) { Class c = ERXPatcher.classForName(className); index = (ERIndex) _NSUtilities.instantiateObject(c, new Class[] { String.class, NSDictionary.class }, new Object[] { key, dict }, true, false); } else { index = new ERAutoIndex(key, dict); } // Add the index addIndex(key, index); } @Override public void finishInitialization() { // load index definition files into indices loadIndexDefinitions(); } public static ERIndexing indexing() { return sharedInstance(ERIndexing.class); } public void clear() { new ERIndexer(indexing().indices.allValues()).clear(); } }