package com.tinkerpop.rexster.server; import com.tinkerpop.rexster.RexsterApplicationGraph; import com.tinkerpop.rexster.Tokens; import com.tinkerpop.rexster.config.GraphConfigurationContainer; import com.tinkerpop.rexster.config.GraphConfigurationException; import com.tinkerpop.rexster.util.HierarchicalConfigurationComparator; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Configure multiple graphs in rexster via XML based Apache Configuration. This is the standard way Rexster is * configured in standalone operations. * * @author Stephen Mallette (http://stephen.genoprime.com) */ public class XmlRexsterApplication extends AbstractMapRexsterApplication { private static final Logger logger = Logger.getLogger(XmlRexsterApplication.class); private static final HierarchicalConfigurationComparator configComparator = new HierarchicalConfigurationComparator(); private List<HierarchicalConfiguration> previousConfigurations; /** * Create new XmlRexsterApplication * * @param graphConfigs graph configuration settings. */ public XmlRexsterApplication(final List<HierarchicalConfiguration> graphConfigs) { this.reconfigure(graphConfigs); } /** * Create new XmlRexsterApplication */ public XmlRexsterApplication(final RexsterProperties properties) { properties.addListener(new RexsterProperties.RexsterPropertiesListener() { @Override public void propertiesChanged(XMLConfiguration configuration) { reconfigure(properties.getGraphConfigurations()); } }); this.reconfigure(properties.getGraphConfigurations()); } synchronized void reconfigure(final List<HierarchicalConfiguration> graphConfigs) { try { final List<RexsterApplicationGraph> graphsToKill = new ArrayList<RexsterApplicationGraph>(); final List<HierarchicalConfiguration> differentConfigs = new ArrayList<HierarchicalConfiguration>(); // look for new or different configurations for (HierarchicalConfiguration gc : graphConfigs) { final HierarchicalConfiguration foundGc = find(gc); if (foundGc == null || !configComparator.compare(foundGc, gc)) { differentConfigs.add(gc); // this could be null if the graph was not found and is new to the config final RexsterApplicationGraph ragToKill = this.graphs.get(gc.getString(Tokens.REXSTER_GRAPH_NAME)); if (ragToKill != null) { graphsToKill.add(ragToKill); } } } // remove any graphs that were killed out of the config for (Map.Entry<String, RexsterApplicationGraph> rag : this.graphs.entrySet()) { boolean found = false; for (HierarchicalConfiguration gc : graphConfigs) { if (gc.getString(Tokens.REXSTER_GRAPH_NAME).equals(rag.getKey())) { found = true; break; } } if (!found) { graphsToKill.add(rag.getValue()); } } // shutdown the graphs that need to be killed and remove them for (RexsterApplicationGraph graphToKill : graphsToKill) { try { // call shutdown on the unwrapped graph as some wrappers don't allow shutdown() to be called. graphToKill.getUnwrappedGraph().shutdown(); } catch (Exception ex) { logger.error(String.format("Error while shutting down graph [%s] after finding it no longer configured.", graphToKill), ex); } finally { graphs.remove(graphToKill.getGraphName()); graphToKill = null; logger.info(String.format("Shutdown graph [%s]. It is no longer configured.", graphToKill)); } } // build configurations for the new/different graph configurations only final GraphConfigurationContainer container = new GraphConfigurationContainer(differentConfigs); final Map<String, RexsterApplicationGraph> configuredGraphs = container.getApplicationGraphs(); graphs.putAll(configuredGraphs); // the current configuration becomes the new "previous" configuration for future evaluations on // what things have changed in the config previousConfigurations = graphConfigs; } catch (GraphConfigurationException gce) { logger.error("Graph initialization failed. Check the graph configuration in rexster.xml."); } } private HierarchicalConfiguration find(final HierarchicalConfiguration hcToFind) { if (this.previousConfigurations == null) { return null; } for (HierarchicalConfiguration hc : this.previousConfigurations) { final String nameToFind = hcToFind.getString(Tokens.REXSTER_GRAPH_NAME); if (nameToFind.equals(hc.getString(Tokens.REXSTER_GRAPH_NAME))) { return hc; } } return null; } }