/* * Copyright (c) 2013 Eike Stepper (Berlin, Germany) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Christian W. Damus (CEA LIST) - initial API and implementation */ package org.eclipse.emf.cdo.server.internal.admin; import org.eclipse.emf.cdo.common.admin.CDOAdmin; import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.admin.CDORepositoryConfigurationManager; import org.eclipse.emf.cdo.server.internal.admin.bundle.OM; import org.eclipse.emf.cdo.server.spi.admin.CDOAdminHandler; import org.eclipse.emf.cdo.server.spi.admin.CDOAdminHandler2; import org.eclipse.emf.cdo.server.spi.security.SecurityManagerFactory; import org.eclipse.net4j.util.container.IManagedContainer; import org.eclipse.net4j.util.container.IManagedContainer.ContainerAware; import org.eclipse.net4j.util.container.IPluginContainer; import org.eclipse.net4j.util.factory.ProductCreationException; import org.eclipse.net4j.util.lifecycle.ILifecycle; import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.emf.common.util.WrappedException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.IOException; import java.io.StringReader; import java.util.Map; /** * @author Christian W. Damus (CEA LIST) */ public class DefaultCDOAdminHandler implements CDOAdminHandler2, ContainerAware { private final String type; private IManagedContainer container = IPluginContainer.INSTANCE; private CDORepositoryConfigurationManager configurationManager; public DefaultCDOAdminHandler(String type) { this.type = type; } public String getType() { return type; } public IManagedContainer getManagedContainer() { return container; } public void setManagedContainer(IManagedContainer container) { this.container = container; } public IRepository createRepository(String name, Map<String, Object> properties) { CDORepositoryConfigurationManager configManager = requireConfigurationManager(); try { Document configDocument = getConfiguration(name, properties); IRepository result = configManager.addRepository(name, configDocument); LifecycleUtil.activate(result); OM.LOG.info("Repository created: " + name); return result; } catch (RuntimeException ex) { throw ex; } catch (Exception ex) { throw new WrappedException("Failed to add repository.", ex); } } public void deleteRepository(IRepository delegate) { CDORepositoryConfigurationManager configManager = requireConfigurationManager(); configManager.removeRepository(delegate); OM.LOG.info("Repository deleted: " + delegate.getName()); } public boolean canDelete(IRepository delegate) { CDORepositoryConfigurationManager configManager = getConfigurationManager(); return configManager != null && configManager.canRemoveRepository(delegate); } public void authenticateAdministrator() throws SecurityException { CDORepositoryConfigurationManager configManager = requireConfigurationManager(); configManager.authenticateAdministrator(); } protected CDORepositoryConfigurationManager getConfigurationManager() { if (configurationManager == null) { IManagedContainer container = requireContainer(); if (container == null) { throw new IllegalStateException("No container."); //$NON-NLS-1$ } Object[] available = container.getElements(CDORepositoryConfigurationManager.Factory.PRODUCT_GROUP); if (available.length > 0) { configurationManager = (CDORepositoryConfigurationManager)available[0]; configurationManager.addListener(new LifecycleEventAdapter() { @Override protected void onDeactivated(ILifecycle lifecycle) { configurationManager = null; lifecycle.removeListener(this); } }); } } return configurationManager; } protected IManagedContainer requireContainer() { IManagedContainer result = getManagedContainer(); if (result == null) { throw new IllegalStateException("No container."); //$NON-NLS-1$ } return result; } protected CDORepositoryConfigurationManager requireConfigurationManager() { CDORepositoryConfigurationManager result = getConfigurationManager(); if (result == null) { throw new SecurityException("Remote administration of repositories requires a repository configuration manager."); //$NON-NLS-1$ } return result; } protected Document getConfiguration(String name, Map<String, Object> properties) throws Exception { // Make a copy that we can modify properties = new java.util.HashMap<String, Object>(properties); DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); // Get some known configuration templates boolean hasSecurityManager = Boolean.TRUE.equals(properties.remove(CDOAdmin.PROPERTY_SECURITY_MANAGER)); boolean hasHomeFolders = Boolean.TRUE.equals(properties.remove(CDOAdmin.PROPERTY_SECURITY_HOME_FOLDERS)); // Parse the store XML. Do this now so that the applicable properties are removed from the map Element storeConfig = parseStoreConfig(docBuilder, properties); Document result = docBuilder.newDocument(); Element repository = result.createElement("repository"); //$NON-NLS-1$ repository.setAttribute("name", name); //$NON-NLS-1$ result.appendChild(repository); // apply name/value properties of the repository for (Map.Entry<String, Object> entry : properties.entrySet()) { Element property = result.createElement("property"); //$NON-NLS-1$ property.setAttribute("name", entry.getKey()); //$NON-NLS-1$ property.setAttribute("value", stringValue(entry.getValue())); //$NON-NLS-1$ repository.appendChild(property); } if (hasSecurityManager) { configureSecurity(result, repository, hasHomeFolders); } Node adopted = result.adoptNode(storeConfig); if (adopted == null) { // OK, then import it (which creates a copy) adopted = result.importNode(storeConfig, true); } repository.appendChild(adopted); return result; } protected String stringValue(Object object) { return object == null ? "" : object.toString(); //$NON-NLS-1$ } protected void configureSecurity(Document configuration, Element repository, boolean hasHomeFolders) { String realmPath = "/security"; //$NON-NLS-1$ if (hasHomeFolders) { realmPath = realmPath + ":annotation:home(/home)"; //$NON-NLS-1$ } Element securityManager = configuration.createElement("securityManager"); //$NON-NLS-1$ securityManager.setAttribute("type", SecurityManagerFactory.Default.TYPE); //$NON-NLS-1$ securityManager.setAttribute("description", realmPath); //$NON-NLS-1$ repository.appendChild(securityManager); } protected Element parseStoreConfig(DocumentBuilder documentBuilder, Map<String, Object> properties) { String storeConfigText = stringValue(properties.remove(CDOAdmin.PROPERTY_STORE_XML_CONFIG)); try { Document document = documentBuilder.parse(new InputSource(new StringReader(storeConfigText))); return document.getDocumentElement(); } catch (IOException ex) { throw new WrappedException("I/O exception in parsing in-memory XML string", ex); //$NON-NLS-1$ } catch (SAXException ex) { throw new IllegalArgumentException("Invalid XML store configuration.", ex); //$NON-NLS-1$ } } /** * @author Christian W. Damus (CEA LIST) */ public static final class Factory extends CDOAdminHandler.Factory { public static final String TYPE = CDOAdmin.DEFAULT_TYPE; public Factory() { super(TYPE); } @Override public CDOAdminHandler create(String description) throws ProductCreationException { return new DefaultCDOAdminHandler(TYPE); } } }