package org.safehaus.penrose.partition; import org.safehaus.penrose.adapter.AdapterConfig; import org.safehaus.penrose.PenroseConfig; import org.safehaus.penrose.Penrose; import org.safehaus.penrose.module.ModuleReader; import org.safehaus.penrose.module.ModuleWriter; import org.safehaus.penrose.mapping.MappingReader; import org.safehaus.penrose.mapping.MappingWriter; import org.safehaus.penrose.connection.ConnectionConfig; import org.safehaus.penrose.connection.ConnectionReader; import org.safehaus.penrose.connection.ConnectionWriter; import org.safehaus.penrose.directory.*; import org.safehaus.penrose.ldap.DN; import org.safehaus.penrose.naming.PenroseContext; import org.safehaus.penrose.partition.event.PartitionEvent; import org.safehaus.penrose.partition.event.PartitionListener; import org.safehaus.penrose.source.SourceConfig; import org.safehaus.penrose.source.SourceReader; import org.safehaus.penrose.source.SourceWriter; import org.safehaus.penrose.util.TextUtil; import org.safehaus.penrose.util.PenroseClassLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FilenameFilter; import java.util.*; /** * @author Endi S. Dewata */ public class PartitionManager { public Logger log = LoggerFactory.getLogger(getClass()); protected File home; protected File partitionsDir; protected File confDir; PenroseConfig penroseConfig; PenroseContext penroseContext; Map<String,Partition> partitions = new LinkedHashMap<String,Partition>(); PartitionConfigManager partitionConfigManager = new PartitionConfigManager(); Queue<String> queue = new LinkedList<String>(); Collection<PartitionListener> listeners = new LinkedHashSet<PartitionListener>(); public PartitionManager(File home, PenroseConfig penroseConfig, PenroseContext penroseContext) { this.home = home; this.penroseConfig = penroseConfig; this.penroseContext = penroseContext; this.partitionsDir = new File(home, "partitions"); this.confDir = new File(home, "conf"); } public PartitionConfigManager getPartitionConfigManager() { return partitionConfigManager; } public void addPartitionConfig(PartitionConfig partitionConfig) throws Exception { log.debug("Adding partition config "+partitionConfig.getName()+"."); partitionConfigManager.addPartitionConfig(partitionConfig); if (!listeners.isEmpty()) { //log.debug("Invoking "+listeners.size()+" listener(s)."); PartitionEvent event = new PartitionEvent(PartitionEvent.PARTITION_ADDED, partitionConfig.getName()); for (PartitionListener listener : listeners) { listener.partitionAdded(event); } } } public File getPartitionsDir() { return partitionsDir; } public Queue<String> getQueue() { return queue; } public void startPartitions() throws Exception { loadRootPartition(); startPartition(PartitionConfig.ROOT); for (String partitionName : getAvailablePartitionNames()) { try { loadPartition(partitionName); } catch (Exception e) { Penrose.errorLog.error("Failed loading partition "+partitionName+".", e); } } Collection<String> partitionNames = new ArrayList<String>(); partitionNames.addAll(partitionConfigManager.getPartitionNames()); for (String partitionName : partitionNames) { if (PartitionConfig.ROOT.equals(partitionName)) continue; try { startPartition(partitionName); } catch (Exception e) { Penrose.errorLog.error("Failed starting partition "+partitionName+".", e); } } while (!queue.isEmpty()) { String partitionName = queue.remove(); try { loadPartition(partitionName); } catch (Exception e) { Penrose.errorLog.error("Failed loading partition "+partitionName+".", e); continue; } try { startPartition(partitionName); } catch (Exception e) { Penrose.errorLog.error("Failed starting partition "+partitionName+".", e); } } } public PartitionConfig loadRootPartition() throws Exception { boolean debug = log.isDebugEnabled(); if (debug) { log.debug(TextUtil.repeat("-", 70)); log.debug("Loading root partition."); } PartitionConfig partitionConfig = new PartitionConfig(); partitionConfig.setName(PartitionConfig.ROOT); for (AdapterConfig adapterConfig : penroseConfig.getAdapterConfigs()) { partitionConfig.addAdapterConfig(adapterConfig); } File connectionsXml = new File(confDir, "connections.xml"); ConnectionReader connectionReader = new ConnectionReader(); connectionReader.read(connectionsXml, partitionConfig.getConnectionConfigManager()); File sourcesXml = new File(confDir, "sources.xml"); SourceReader sourceReader = new SourceReader(); sourceReader.read(sourcesXml, partitionConfig.getSourceConfigManager()); File mappingsXml = new File(confDir, "mappings.xml"); MappingReader mappingReader = new MappingReader(); mappingReader.read(mappingsXml, partitionConfig.getMappingConfigManager()); File directoryXml = new File(confDir, "directory.xml"); DirectoryReader directoryReader = new DirectoryReader(); directoryReader.read(directoryXml, partitionConfig.getDirectoryConfig()); File modulesXml = new File(confDir, "modules.xml"); ModuleReader moduleReader = new ModuleReader(); moduleReader.read(modulesXml, partitionConfig.getModuleConfigManager()); addPartitionConfig(partitionConfig); if (debug) log.debug("Root partition loaded."); return partitionConfig; } public void storeRootPartition() throws Exception { boolean debug = log.isDebugEnabled(); if (debug) { log.debug(TextUtil.repeat("-", 70)); log.debug("Storing root partition."); } PartitionConfig partitionConfig = partitionConfigManager.getPartitionConfig(PartitionConfig.ROOT); File connectionsXml = new File(confDir, "connections.xml"); ConnectionWriter connectionWriter = new ConnectionWriter(); connectionWriter.write(connectionsXml, partitionConfig.getConnectionConfigManager()); File sourcesXml = new File(confDir, "sources.xml"); SourceWriter sourceWriter = new SourceWriter(); sourceWriter.write(sourcesXml, partitionConfig.getSourceConfigManager()); File mappingsXml = new File(confDir, "mappings.xml"); MappingWriter mappingWriter = new MappingWriter(); mappingWriter.write(mappingsXml, partitionConfig.getMappingConfigManager()); File directoryXml = new File(confDir, "directory.xml"); DirectoryWriter directoryWriter = new DirectoryWriter(); directoryWriter.write(directoryXml, partitionConfig.getDirectoryConfig()); File modulesXml = new File(confDir, "modules.xml"); ModuleWriter moduleWriter = new ModuleWriter(); moduleWriter.write(modulesXml, partitionConfig.getModuleConfigManager()); if (debug) log.debug("Root partition stored."); } public PartitionConfig loadPartition(String partitionName) throws Exception { boolean debug = log.isDebugEnabled(); PartitionConfig partitionConfig = partitionConfigManager.getPartitionConfig(partitionName); if (partitionConfig != null) { log.debug("Partition "+partitionName+" is already loaded."); return partitionConfig; } if (debug) { log.debug(TextUtil.repeat("-", 70)); log.debug("Loading partition "+partitionName+"."); } partitionConfig = new PartitionConfig(); partitionConfig.setName(partitionName); File partitionDir = new File(partitionsDir, partitionName); File baseDir = new File(partitionDir, "DIR-INF"); PartitionReader reader = new PartitionReader(); reader.read(baseDir, partitionConfig); File connectionsXml = new File(baseDir, "connections.xml"); ConnectionReader connectionReader = new ConnectionReader(); connectionReader.read(connectionsXml, partitionConfig.getConnectionConfigManager()); File sourcesXml = new File(baseDir, "sources.xml"); SourceReader sourceReader = new SourceReader(); sourceReader.read(sourcesXml, partitionConfig.getSourceConfigManager()); File mappingsXml = new File(baseDir, "mappings.xml"); MappingReader mappingReader = new MappingReader(); mappingReader.read(mappingsXml, partitionConfig.getMappingConfigManager()); File directoryXml = new File(baseDir, "directory.xml"); DirectoryReader directoryReader = new DirectoryReader(); directoryReader.read(directoryXml, partitionConfig.getDirectoryConfig()); File modulesXml = new File(baseDir, "modules.xml"); ModuleReader moduleReader = new ModuleReader(); moduleReader.read(modulesXml, partitionConfig.getModuleConfigManager()); addPartitionConfig(partitionConfig); if (debug) log.debug("Partition "+partitionName+" loaded."); return partitionConfig; } public void storePartition(String partitionName) throws Exception { boolean debug = log.isDebugEnabled(); if (PartitionConfig.ROOT.equals(partitionName)) { storeRootPartition(); return; } if (debug) { log.debug(TextUtil.repeat("-", 70)); log.debug("Storing partition "+partitionName+"."); } PartitionConfig partitionConfig = partitionConfigManager.getPartitionConfig(partitionName); File partitionDir = new File(partitionsDir, partitionName); File dirInfDir = new File(partitionDir, "DIR-INF"); PartitionWriter partitionWriter = new PartitionWriter(); partitionWriter.write(dirInfDir, partitionConfig); File connectionsXml = new File(dirInfDir, "connections.xml"); ConnectionWriter connectionWriter = new ConnectionWriter(); connectionWriter.write(connectionsXml, partitionConfig.getConnectionConfigManager()); File sourcesXml = new File(dirInfDir, "sources.xml"); SourceWriter sourceWriter = new SourceWriter(); sourceWriter.write(sourcesXml, partitionConfig.getSourceConfigManager()); File mappingsXml = new File(dirInfDir, "mappings.xml"); MappingWriter mappingWriter = new MappingWriter(); mappingWriter.write(mappingsXml, partitionConfig.getMappingConfigManager()); File directoryXml = new File(dirInfDir, "directory.xml"); DirectoryWriter directoryWriter = new DirectoryWriter(); directoryWriter.write(directoryXml, partitionConfig.getDirectoryConfig()); File modulesXml = new File(dirInfDir, "modules.xml"); ModuleWriter moduleWriter = new ModuleWriter(); moduleWriter.write(modulesXml, partitionConfig.getModuleConfigManager()); if (debug) log.debug("Partition "+partitionName+" stored."); } public void startPartition(String partitionName) throws Exception { boolean debug = log.isDebugEnabled(); Partition partition = partitions.get(partitionName); if (partition != null) { log.debug("Partition "+partitionName+" already started."); return; } PartitionConfig partitionConfig = partitionConfigManager.getPartitionConfig(partitionName); if (partitionConfig == null) { Penrose.errorLog.error("Can't start partition "+partitionName+": Partition not found."); return; } if (!partitionConfig.isEnabled()) { log.debug("Partition "+partitionName+" disabled."); return; } for (String depend : partitionConfig.getDepends()) { if (partitionConfigManager.getPartitionConfig(depend) == null) { Penrose.errorLog.error("Can't start partition "+partitionName+": Missing dependency ["+depend+"]."); return; } log.debug("Partition "+partitionName+" is dependent on partition "+depend+"."); startPartition(depend); } if (debug) { log.debug(TextUtil.repeat("-", 70)); log.debug("Starting partition "+partitionName+"."); } PartitionContext partitionContext = createPartitionContext(partitionConfig); partition = createPartition(partitionConfig, partitionContext); log.debug("Adding partition "+partitionConfig.getName()+"."); partitions.put(partitionConfig.getName(), partition); partition.init(partitionConfig, partitionContext); if (!listeners.isEmpty()) { //log.debug("Invoking "+listeners.size()+" listener(s)."); PartitionEvent event = new PartitionEvent(PartitionEvent.PARTITION_STARTED, partitionName); for (PartitionListener listener : listeners) { listener.partitionStarted(event); } } log.debug("Partition "+partitionName+" started."); } public PartitionContext createPartitionContext(PartitionConfig partitionConfig) throws Exception { String partitionName = partitionConfig.getName(); PartitionContext partitionContext = new PartitionContext(); if (PartitionConfig.ROOT.equals(partitionName)) { partitionContext.setPath(null); partitionContext.setClassLoader(getClass().getClassLoader()); } else { File partitionDir = new File(partitionsDir, partitionConfig.getName()); partitionContext.setPath(partitionsDir == null ? null : partitionDir); ClassLoader classLoader = new PartitionClassLoader(partitionDir, getClass().getClassLoader()); partitionContext.setClassLoader(classLoader); } partitionContext.setPenroseConfig(penroseConfig); partitionContext.setPenroseContext(penroseContext); partitionContext.setPartitionManager(penroseContext.getPartitionManager()); return partitionContext; } public Partition createPartition(PartitionConfig partitionConfig, PartitionContext partitionContext) throws Exception { Partition partition; String className = partitionConfig.getPartitionClass(); if (className == null) { partition = new Partition(); } else { ClassLoader classLoader = partitionContext.getClassLoader(); Class clazz = classLoader.loadClass(className); partition = (Partition)clazz.newInstance(); } return partition; } public void stopPartitions() throws Exception { List<String> list = new ArrayList<String>(); for (String partitionName : partitions.keySet()) { list.add(0, partitionName); } for (String partitionName : list) { try { stopPartition(partitionName); removePartition(partitionName); } catch (Exception e) { Penrose.errorLog.error(e.getMessage(), e); } } } public void stopPartition(String partitionName) throws Exception { boolean debug = log.isDebugEnabled(); if (debug) { log.debug(TextUtil.repeat("-", 70)); log.debug("Stopping partition "+partitionName+"."); } Partition partition = partitions.get(partitionName); if (partition == null) { log.debug("Partition "+partitionName+" not started."); return; } partition.destroy(); partitions.remove(partitionName); if (!listeners.isEmpty()) { //log.debug("Invoking "+listeners.size()+" listener(s)."); PartitionEvent event = new PartitionEvent(PartitionEvent.PARTITION_STOPPED, partitionName); for (PartitionListener listener : listeners) { listener.partitionStopped(event); } } log.debug("Partition "+partitionName+" stopped."); } public void removePartition(String partitionName) throws Exception { PartitionConfig partitionConfig = partitionConfigManager.getPartitionConfig(partitionName); if (!listeners.isEmpty()) { //log.debug("Invoking "+listeners.size()+" listener(s)."); PartitionEvent event = new PartitionEvent(PartitionEvent.PARTITION_REMOVED, partitionConfig.getName()); for (PartitionListener listener : listeners) { listener.partitionRemoved(event); } } partitionConfigManager.removePartitionConfig(partitionName); log.debug("Partition "+partitionName+" removed."); } public void clear() throws Exception { partitionConfigManager.clear(); partitions.clear(); } public Partition getPartition(String name) { return partitions.get(name); } public PartitionConfig getPartitionConfig(String name) { return partitionConfigManager.getPartitionConfig(name); } public Collection<PartitionConfig> getPartitionConfigs() { return partitionConfigManager.getPartitionConfigs(); } public Partition getPartition(EntrySourceConfig sourceMapping) throws Exception { if (sourceMapping == null) return null; String sourceName = sourceMapping.getSourceName(); for (Partition partition : partitions.values()) { PartitionConfig partitionConfig = partition.getPartitionConfig(); if (partitionConfig.getSourceConfigManager().getSourceConfig(sourceName) != null) return partition; } return null; } public Partition getPartition(SourceConfig sourceConfig) throws Exception { if (sourceConfig == null) return null; String connectionName = sourceConfig.getConnectionName(); for (Partition partition : partitions.values()) { PartitionConfig partitionConfig = partition.getPartitionConfig(); if (partitionConfig.getConnectionConfigManager().getConnectionConfig(connectionName) != null) return partition; } return null; } public Partition getPartition(ConnectionConfig connectionConfig) throws Exception { if (connectionConfig == null) return null; String connectionName = connectionConfig.getName(); for (Partition partition : partitions.values()) { PartitionConfig partitionConfig = partition.getPartitionConfig(); if (partitionConfig.getConnectionConfigManager().getConnectionConfig(connectionName) != null) return partition; } return null; } public Partition getPartition(DN dn) throws Exception { boolean debug = log.isDebugEnabled(); if (debug) log.debug("Searching partition for \""+dn+"\"."); Collection<Partition> results = getPartitions(dn); if (results.isEmpty()) { if (debug) log.debug("Returning root partition."); return getPartition(PartitionConfig.ROOT); } Partition partition = results.iterator().next(); if (debug) log.debug("Returning partition "+partition.getName()+"."); return partition; } public Collection<Partition> getPartitions(DN dn) throws Exception { Collection<Partition> results = new HashSet<Partition>(); for (Entry entry : findEntries(dn)) { Partition partition = entry.getPartition(); results.add(partition); } return results; } public Collection<Entry> findEntries(DN dn) throws Exception { Collection<Entry> results = new ArrayList<Entry>(); for (Partition partition : partitions.values()) { //if (debug) log.debug("Searching for \""+dn+"\" in "+partition.getName()+"."); Directory directory = partition.getDirectory(); results.addAll(directory.findEntries(dn)); } return results; } /* public Collection<Partition> getPartitions(DN dn) throws Exception { Collection<Partition> results = new ArrayList<Partition>(); if (debug) log.debug("Finding partitions for \""+dn+"\"."); if (dn == null) { log.debug("DN is null."); //results.add(getPartition(PartitionConfig.ROOT)); return results; } Partition p = getPartition(PartitionConfig.ROOT); if (dn.isEmpty()) { log.debug("Root DSE."); results.add(p); return results; } DN s = null; for (Partition partition : partitions.values()) { if (debug) log.debug("Checking "+partition.getName()+" partition."); PartitionConfig partitionConfig = partition.getPartitionConfig(); Collection<DN> suffixes = partitionConfig.getDirectoryConfig().getSuffixes(); for (DN suffix : suffixes) { if (suffix.isEmpty() && dn.isEmpty() // Root DSE || dn.endsWith(suffix)) { if (s == null || s.getSize() < suffix.getSize()) { p = partition; s = suffix; } } } } if (debug) { if (p == null) { log.debug("Partition not found."); } else { log.debug("Found partition "+p.getName()+"."); } } return results; } */ public Collection<Partition> getPartitions() { return partitions.values(); } public Collection<String> getAvailablePartitionNames() throws Exception { Collection<String> list = new TreeSet<String>(); for (File partitionDir : partitionsDir.listFiles()) { list.add(partitionDir.getName()); } return list; } public Collection<String> getPartitionNames() { return partitions.keySet(); } public int size() { return partitions.size(); } public File getHome() { return home; } public void setHome(File home) { this.home = home; } public void setPartitionsDir(File partitionsDir) { this.partitionsDir = partitionsDir; } public File getConfDir() { return confDir; } public void setConfDir(File confDir) { this.confDir = confDir; } public void addListener(PartitionListener listener) { listeners.add(listener); } public void removeListener(PartitionListener listener) { listeners.remove(listener); } }