Added: ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceManagerImpl.java URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceManagerImpl.java?rev=1569429&view=auto ============================================================================== --- ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceManagerImpl.java (added) +++ ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceManagerImpl.java Tue Feb 18 17:00:32 2014 @@ -0,0 +1,293 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.ace.client.workspace.impl; + +import java.io.IOException; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.ace.authentication.api.AuthenticationService; +import org.apache.ace.client.repository.SessionFactory; +import org.apache.ace.client.workspace.Workspace; +import org.apache.ace.client.workspace.WorkspaceManager; +import org.apache.felix.dm.Component; +import org.apache.felix.dm.DependencyManager; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedService; +import org.osgi.service.log.LogService; +import org.osgi.service.useradmin.User; +import org.osgi.service.useradmin.UserAdmin; + +@SuppressWarnings("rawtypes") +public class WorkspaceManagerImpl implements ManagedService, WorkspaceManager { + /** A boolean denoting whether or not authentication is enabled. */ + private static final String KEY_USE_AUTHENTICATION = "authentication.enabled"; + /** URL of the repository to talk to. */ + private static final String KEY_REPOSITORY_URL = "repository.url"; + /** Name of the customer. */ + private static final String KEY_CUSTOMER_NAME = "customer.name"; + /** Name of the store repository. */ + private static final String KEY_STORE_REPOSITORY_NAME = "store.repository.name"; + /** Name of the distribution repository. */ + private static final String KEY_DISTRIBUTION_REPOSITORY_NAME = "distribution.repository.name"; + /** Name of the deployment repository. */ + private static final String KEY_DEPLOYMENT_REPOSITORY_NAME = "deployment.repository.name"; + /** Name of the user to log in as, in case no actual authentication is used. */ + private static final String KEY_USER_NAME = "user.name"; + + private static long m_sessionID = 1; + private volatile LogService m_logger; + private volatile DependencyManager m_dm; + private volatile SessionFactory m_sessionFactory; + + private volatile AuthenticationService m_authenticationService; + private volatile UserAdmin m_userAdmin; + + private final Map m_workspaces; + private final Map m_workspaceComponents; + + private boolean m_useAuthentication; + private String m_repositoryURL; + private String m_customerName; + private String m_storeRepositoryName; + private String m_targetRepositoryName; + private String m_deploymentRepositoryName; + private String m_serverUser; + + public WorkspaceManagerImpl() { + m_workspaces = new HashMap(); + m_workspaceComponents = new HashMap(); + } + + public void init(Component component) { + addDependency(component, AuthenticationService.class, m_useAuthentication); + addDependency(component, UserAdmin.class, true); + } + + private void addDependency(Component component, Class service, boolean isRequired) { + component.add(component.getDependencyManager().createServiceDependency().setService(service) + .setRequired(isRequired).setInstanceBound(true)); + } + + public void destroy() { + Set keySet = m_workspaces.keySet(); + if (!keySet.isEmpty()) { + String[] keys = keySet.toArray(new String[keySet.size()]); + for (String key : keys) { + try { + removeWorkspace(key); + } + catch (IOException e) { + m_logger.log(LogService.LOG_WARNING, "Could not properly remove workspace.", e); + } + } + } + } + + @Override + public void updated(Dictionary properties) throws ConfigurationException { + // First check whether all mandatory configuration keys are available... + String useAuth = getProperty(properties, KEY_USE_AUTHENTICATION); + if (useAuth == null || !("true".equalsIgnoreCase(useAuth) || "false".equalsIgnoreCase(useAuth))) { + throw new ConfigurationException(KEY_USE_AUTHENTICATION, "Missing or invalid value!"); + } + + // Note that configuration changes are only applied to new work areas, started after the + // configuration was changed. No attempt is done to "fix" existing work areas, although we + // might consider flushing/invalidating them. + synchronized (m_workspaces) { + m_useAuthentication = Boolean.valueOf(useAuth); + m_repositoryURL = getProperty(properties, KEY_REPOSITORY_URL, "http://localhost:8080/repository"); + m_customerName = getProperty(properties, KEY_CUSTOMER_NAME, "apache"); + m_storeRepositoryName = getProperty(properties, KEY_STORE_REPOSITORY_NAME, "shop"); + m_targetRepositoryName = getProperty(properties, KEY_DISTRIBUTION_REPOSITORY_NAME, "target"); + m_deploymentRepositoryName = getProperty(properties, KEY_DEPLOYMENT_REPOSITORY_NAME, "deployment"); + m_serverUser = getProperty(properties, KEY_USER_NAME, "d"); + } + } + + @Override + public Workspace createWorkspace(Map sessionConfiguration, Object... authenticationContext) throws IOException { + // TODO get data from post body (if no data, assume latest??) -> for now + // always assume latest + final String sessionID; + final Workspace workspace; + final Component component; + + synchronized (m_workspaces) { + sessionID = "rest-" + m_sessionID++; + workspace = new WorkspaceImpl(sessionID, m_repositoryURL, m_customerName, m_storeRepositoryName, + m_targetRepositoryName, m_deploymentRepositoryName); + m_workspaces.put(sessionID, workspace); + + component = m_dm.createComponent().setImplementation(workspace); + m_workspaceComponents.put(sessionID, component); + } + // any parameters supplied in this call are passed on to the session + // factory, so you can use these to configure your session + m_sessionFactory.createSession(sessionID, sessionConfiguration); + m_dm.add(component); + + User user; + if (m_useAuthentication) { + // Use the authentication service to authenticate the given + // request... + user = m_authenticationService.authenticate(authenticationContext); + } + else { + // Use the "hardcoded" user to login with... + user = m_userAdmin.getUser("username", m_serverUser); + } + + if (user == null || !workspace.login(user)) { + return null; + } + else { + return workspace; + } + } + + @Override + public Workspace getWorkspace(String id) { + Workspace workspace; + synchronized (m_workspaces) { + workspace = m_workspaces.get(id); + } + return workspace; + } + + @Override + public void removeWorkspace(final String id) throws IOException { + final Workspace workspace; + final Component component; + + synchronized (m_workspaces) { + workspace = m_workspaces.remove(id); + component = m_workspaceComponents.remove(id); + } + + if ((workspace != null) && (component != null)) { + try { + workspace.logout(); + } + finally { + m_dm.remove(component); + m_sessionFactory.destroySession(id); + } + } + } + + @Override + public Workspace cw() throws IOException { + return cw(m_customerName, m_customerName, m_customerName, null); + } + + @Override + public Workspace cw(Map sessionConfiguration) throws IOException { + return cw(m_customerName, m_customerName, m_customerName, sessionConfiguration); + } + + @Override + public Workspace cw(String storeCustomerName, String targetCustomerName, String deploymentCustomerName) + throws IOException { + return cw(storeCustomerName, targetCustomerName, deploymentCustomerName, null); + } + + @Override + public Workspace cw(String storeCustomerName, String targetCustomerName, String deploymentCustomerName, + Map sessionConfiguration) throws IOException { + final String sessionID; + final Workspace workspace; + final Component component; + + synchronized (m_workspaces) { + sessionID = "shell-" + m_sessionID++; + workspace = new WorkspaceImpl(sessionID, m_repositoryURL, storeCustomerName, m_storeRepositoryName, + targetCustomerName, m_targetRepositoryName, deploymentCustomerName, m_deploymentRepositoryName); + m_workspaces.put(sessionID, workspace); + + component = m_dm.createComponent().setImplementation(workspace); + m_workspaceComponents.put(sessionID, component); + } + m_sessionFactory.createSession(sessionID, sessionConfiguration); + m_dm.add(component); + + // Use the "hardcoded" user to login with... + User user = m_userAdmin.getUser("username", m_serverUser); + if (user == null || !workspace.login(user)) { + return null; + } + else { + return workspace; + } + } + + @Override + public Workspace gw(String id) { + return getWorkspace(id); + } + + @Override + public void rw(String id) throws IOException { + removeWorkspace(id); + } + + @Override + public void rw(Workspace w) throws IOException { + removeWorkspace(w.getSessionID()); + } + + /** + * Helper method to safely obtain a property value from the given dictionary. + * + * @param properties + * the dictionary to retrieve the value from, can be null; + * @param key + * the name of the property to retrieve, cannot be null; + * @param defaultValue + * the default value to return in case the property does not exist, or the given dictionary was + * null. + * @return a property value, can be null. + */ + String getProperty(Dictionary properties, String key, String defaultValue) { + String value = getProperty(properties, key); + return (value == null) ? defaultValue : value; + } + + /** + * Helper method to safely obtain a property value from the given dictionary. + * + * @param properties + * the dictionary to retrieve the value from, can be null; + * @param key + * the name of the property to retrieve, cannot be null. + * @return a property value, can be null. + */ + String getProperty(Dictionary properties, String key) { + if (properties != null) { + Object value = properties.get(key); + if (value != null && value instanceof String) { + return (String) value; + } + } + return null; + } +} Added: ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/packageinfo URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/packageinfo?rev=1569429&view=auto ============================================================================== --- ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/packageinfo (added) +++ ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/packageinfo Tue Feb 18 17:00:32 2014 @@ -0,0 +1 @@ +version 1.0 \ No newline at end of file Added: ace/trunk/org.apache.ace.client.workspace/test/org/apache/ace/client/workspace/impl/WorkspaceManagerImplTest.java URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/test/org/apache/ace/client/workspace/impl/WorkspaceManagerImplTest.java?rev=1569429&view=auto ============================================================================== --- ace/trunk/org.apache.ace.client.workspace/test/org/apache/ace/client/workspace/impl/WorkspaceManagerImplTest.java (added) +++ ace/trunk/org.apache.ace.client.workspace/test/org/apache/ace/client/workspace/impl/WorkspaceManagerImplTest.java Tue Feb 18 17:00:32 2014 @@ -0,0 +1,20 @@ +package org.apache.ace.client.workspace.impl; + +import static org.apache.ace.test.utils.TestUtils.UNIT; + +import java.util.Properties; + +import org.apache.ace.client.workspace.impl.WorkspaceManagerImpl; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class WorkspaceManagerImplTest { + @SuppressWarnings("serial") + @Test(groups = { UNIT }) + public void testPropertyGetter() { + WorkspaceManagerImpl s = new WorkspaceManagerImpl(); + Assert.assertEquals(s.getProperty(new Properties() {{ put("key", "value"); }}, "key", "notused"), "value"); + Assert.assertEquals(s.getProperty(new Properties() {{ put("unusedkey", "value"); }}, "key", "default"), "default"); + Assert.assertEquals(s.getProperty(null, "key", "default"), "default"); + } +} Modified: ace/trunk/run-client/client.bndrun URL: http://svn.apache.org/viewvc/ace/trunk/run-client/client.bndrun?rev=1569429&r1=1569428&r2=1569429&view=diff ============================================================================== --- ace/trunk/run-client/client.bndrun (original) +++ ace/trunk/run-client/client.bndrun Tue Feb 18 17:00:32 2014 @@ -24,6 +24,7 @@ org.apache.ace.client.repository.helper.configuration;version=latest,\ org.apache.ace.client.repository.impl;version=latest,\ org.apache.ace.client.rest;version=latest,\ + org.apache.ace.client.workspace;version=latest,\ org.apache.ace.configurator.useradmin.task;version=latest,\ org.apache.ace.configurator.impl;version=latest,\ org.apache.ace.connectionfactory;version=latest,\ Modified: ace/trunk/run-client/conf/org.apache.ace.client.rest.cfg URL: http://svn.apache.org/viewvc/ace/trunk/run-client/conf/org.apache.ace.client.rest.cfg?rev=1569429&r1=1569428&r2=1569429&view=diff ============================================================================== --- ace/trunk/run-client/conf/org.apache.ace.client.rest.cfg (original) +++ ace/trunk/run-client/conf/org.apache.ace.client.rest.cfg Tue Feb 18 17:00:32 2014 @@ -1,9 +1,3 @@ org.apache.ace.server.servlet.endpoint=/client -repository.url=http://${org.apache.ace.server}/repository -user.name=d -authentication.enabled=false -customer.name=apache -store.repository.name=shop -distribution.repository.name=target -deployment.repository.name=deployment + Added: ace/trunk/run-client/conf/org.apache.ace.client.workspace.cfg URL: http://svn.apache.org/viewvc/ace/trunk/run-client/conf/org.apache.ace.client.workspace.cfg?rev=1569429&view=auto ============================================================================== --- ace/trunk/run-client/conf/org.apache.ace.client.workspace.cfg (added) +++ ace/trunk/run-client/conf/org.apache.ace.client.workspace.cfg Tue Feb 18 17:00:32 2014 @@ -0,0 +1,8 @@ +repository.url=http://${org.apache.ace.server}/repository +user.name=d +authentication.enabled=false +customer.name=apache +store.repository.name=shop +distribution.repository.name=target +deployment.repository.name=deployment + Modified: ace/trunk/run-server-allinone/conf/org.apache.ace.client.rest.cfg URL: http://svn.apache.org/viewvc/ace/trunk/run-server-allinone/conf/org.apache.ace.client.rest.cfg?rev=1569429&r1=1569428&r2=1569429&view=diff ============================================================================== --- ace/trunk/run-server-allinone/conf/org.apache.ace.client.rest.cfg (original) +++ ace/trunk/run-server-allinone/conf/org.apache.ace.client.rest.cfg Tue Feb 18 17:00:32 2014 @@ -1,9 +0,0 @@ -org.apache.ace.server.servlet.endpoint=/client -repository.url=http://${org.apache.ace.server}/repository -user.name=d -authentication.enabled=false -customer.name=apache -store.repository.name=shop -distribution.repository.name=target -deployment.repository.name=deployment - Added: ace/trunk/run-server-allinone/conf/org.apache.ace.client.workspace.cfg URL: http://svn.apache.org/viewvc/ace/trunk/run-server-allinone/conf/org.apache.ace.client.workspace.cfg?rev=1569429&view=auto ============================================================================== --- ace/trunk/run-server-allinone/conf/org.apache.ace.client.workspace.cfg (added) +++ ace/trunk/run-server-allinone/conf/org.apache.ace.client.workspace.cfg Tue Feb 18 17:00:32 2014 @@ -0,0 +1,8 @@ +repository.url=http://${org.apache.ace.server}/repository +user.name=d +authentication.enabled=false +customer.name=apache +store.repository.name=shop +distribution.repository.name=target +deployment.repository.name=deployment + Modified: ace/trunk/run-server-allinone/server-allinone.bndrun URL: http://svn.apache.org/viewvc/ace/trunk/run-server-allinone/server-allinone.bndrun?rev=1569429&r1=1569428&r2=1569429&view=diff ============================================================================== --- ace/trunk/run-server-allinone/server-allinone.bndrun (original) +++ ace/trunk/run-server-allinone/server-allinone.bndrun Tue Feb 18 17:00:32 2014 @@ -24,6 +24,7 @@ org.apache.ace.client.repository.helper.configuration;version=latest,\ org.apache.ace.client.repository.impl;version=latest,\ org.apache.ace.client.rest;version=latest,\ + org.apache.ace.client.workspace;version=latest,\ org.apache.ace.configurator.useradmin.task;version=latest,\ org.apache.ace.configurator.impl;version=latest,\ org.apache.ace.connectionfactory;version=latest,\