Merge WCM_SERVICES into HEAD 11697, 11698, 11702, 11751, 11801, 11924, 12023, 12073

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@12076 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Mark Rogers
2008-11-21 13:59:09 +00:00
parent 16de2cc1e1
commit cad991db0c
29 changed files with 4443 additions and 692 deletions

View File

@@ -332,6 +332,9 @@
<property name="searchService">
<ref bean="SearchService" />
</property>
<property name="sandboxFactory">
<ref bean="sandboxFactory" />
</property>
</bean>
<!-- AVM Locking. -->

View File

@@ -147,9 +147,6 @@
<property name="serviceRegistry">
<ref bean="ServiceRegistry"/>
</property>
<property name="nameMatcher">
<ref bean="globalPathExcluder"/>
</property>
</bean>
<bean id="crossCopyScript" parent="baseJavaScriptExtension" class="org.alfresco.repo.jscript.CrossRepositoryCopy">

View File

@@ -46,9 +46,6 @@
<property name="serviceRegistry">
<ref bean="ServiceRegistry"/>
</property>
<property name="nameMatcher">
<ref bean="globalPathExcluder"/>
</property>
</bean>
<bean id="sessionTemplateExtension" parent="baseTemplateImplementation" class="org.alfresco.repo.template.Session">

View File

@@ -3,6 +3,8 @@
<beans>
<!-- Web Project Service -->
<!-- Web Project service bean -->
<bean id="WebProjectService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
@@ -49,22 +51,90 @@
<property name="authorityService" ref="AuthorityService"/>
<property name="permissionService" ref="PermissionService"/>
<property name="personService" ref="PersonService"/>
<property name="virtServerRegistry" ref="VirtServerRegistry"/>
<property name="sandboxFactory" ref="sandboxFactory"/>
<property name="virtServerRegistry" ref="VirtServerRegistry"/>
</bean>
<!-- Sandbox service bean -->
<bean id="SandboxService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.alfresco.wcm.sandbox.SandboxService</value>
</property>
<property name="target">
<ref bean="sandboxService"/>
</property>
<property name="interceptorNames">
<list>
<idref local="SandboxService_transaction"/>
<idref bean="AuditMethodInterceptor"/>
<idref bean="exceptionTranslator"/>
<idref local="SandboxService_security"/>
</list>
</property>
</bean>
<!-- Sandbox service transaction bean -->
<bean id="SandboxService_transaction" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="get*">${server.transaction.mode.readOnly}</prop>
<prop key="list*">${server.transaction.mode.readOnly}</prop>
<prop key="is*">${server.transaction.mode.readOnly}</prop>
<prop key="find*">${server.transaction.mode.readOnly}</prop>
<prop key="*">${server.transaction.mode.default}</prop>
</props>
</property>
</bean>
<!-- Sandbox service security bean -->
<bean id="SandboxService_security" class="org.alfresco.repo.security.permissions.impl.AlwaysProceedMethodInterceptor" />
<bean id="sandboxService" class="org.alfresco.wcm.sandbox.SandboxServiceImpl">
<property name="webProjectService" ref="WebProjectService"/>
<property name="sandboxFactory" ref="sandboxFactory"/>
<property name="avmService" ref="AVMService"/>
<property name="avmSyncService" ref="AVMSyncService"/>
<property name="nameMatcher" ref="globalPathExcluder"/>
<property name="virtServerRegistry" ref="VirtServerRegistry"/>
<property name="avmLockingService" ref="AVMLockingService"/>
<property name="actionService" ref="ActionService"/>
<property name="workflowService" ref="WorkflowService"/>
</bean>
<!--
<bean id="sandboxScript" parent="baseJavaScriptExtension" class="org.alfresco.wcm.sandbox.script.Sandboxes">
<property name="extensionName">
<value>sandboxes</value>
</property>
<property name="serviceRegistry" ref="ServiceRegistry"/>
<property name="sandboxService" ref="SandboxService"/>
</bean>
-->
<bean id="sandboxFactory" class="org.alfresco.wcm.sandbox.SandboxFactory">
<property name="nodeService" ref="NodeService"/>
<property name="permissionService" ref="PermissionService"/>
<property name="avmService" ref="AVMService"/>
<property name="avmLockingService" ref="AVMLockingService"/>
<property name="virtServerRegistry" ref="VirtServerRegistry"/>
</bean>
<!-- Java script API ROOT Scopeable object for WCM -->
<bean id="webProjectsScript" parent="baseJavaScriptExtension" class="org.alfresco.wcm.webproject.script.WebProjects">
<property name="extensionName">
<value>webprojects</value>
</property>
<property name="serviceRegistry" ref="ServiceRegistry"/>
<property name="webProjectService" ref="WebProjectService"/>
</bean>
<bean id="sandboxFactory" class="org.alfresco.wcm.sandbox.SandboxFactory">
<property name="nodeService" ref="NodeService"/>
<property name="permissionService" ref="PermissionService"/>
<property name="avmService" ref="AVMService"/>
<property name="sandboxService" ref="SandboxService"/>
</bean>
</beans>

View File

@@ -44,7 +44,7 @@ import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.workflow.WorkflowModel;
import org.alfresco.sandbox.SandboxConstants;
import org.alfresco.wcm.sandbox.SandboxConstants;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
@@ -66,9 +66,8 @@ import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskState;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.DNSNameMangler;
import org.alfresco.util.GUID;
import org.alfresco.util.Pair;
import org.alfresco.wcm.sandbox.SandboxFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -97,6 +96,7 @@ public class AVMExpiredContentProcessor
protected TransactionService transactionService;
protected VirtServerRegistry virtServerRegistry;
protected SearchService searchService;
private SandboxFactory sandboxFactory;
private static Log logger = LogFactory.getLog(AVMExpiredContentProcessor.class);
@@ -172,6 +172,11 @@ public class AVMExpiredContentProcessor
this.avmLockingAwareService = avmLockingAwareService;
}
public void setSandboxFactory(SandboxFactory sandboxFactory)
{
this.sandboxFactory = sandboxFactory;
}
/**
* Executes the expired content processor.
* The work is performed within a transaction running as the system user.
@@ -425,7 +430,7 @@ public class AVMExpiredContentProcessor
NodeRef assignee = this.personService.getPerson(userName);
// create a workflow store layered over the users store
String workflowStoreName = createUserWorkflowSandbox(storeName, userStore);
String workflowStoreName = sandboxFactory.createUserWorkflowSandbox(storeName, userStore);
// create a workflow package with all the expired items
NodeRef workflowPackage = setupWorkflowPackage(workflowStoreName, expiredContent);
@@ -454,124 +459,6 @@ public class AVMExpiredContentProcessor
}
}
/**
* Creates a workflow sandbox for the given user store. This will create a
* workflow sandbox layered over the user's main store.
*
* @param stagingStore The name of the staging store the user sandbox is layered over
* @param userStore The name of the user store to create the workflow for
* @return The store name of the main store in the workflow sandbox
*/
private String createUserWorkflowSandbox(String stagingStore, String userStore)
{
// create the workflow 'main' store
String packageName = "workflow-" + GUID.generate();
String workflowStoreName = userStore + STORE_SEPARATOR + packageName;
this.avmService.createStore(workflowStoreName);
if (logger.isDebugEnabled())
logger.debug("Created user workflow sandbox store: " + workflowStoreName);
// create a layered directory pointing to 'www' in the users store
this.avmService.createLayeredDirectory(
userStore + ":/" + JNDIConstants.DIR_DEFAULT_WWW,
workflowStoreName + ":/", JNDIConstants.DIR_DEFAULT_WWW);
// tag the store with the store type
this.avmService.setStoreProperty(workflowStoreName,
SandboxConstants.PROP_SANDBOX_AUTHOR_WORKFLOW_MAIN,
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the name of the author's store this one is layered over
this.avmService.setStoreProperty(workflowStoreName,
SandboxConstants.PROP_AUTHOR_NAME,
new PropertyValue(DataTypeDefinition.TEXT, userStore));
// tag the store, oddly enough, with its own store name for querying.
this.avmService.setStoreProperty(workflowStoreName,
QName.createQName(null, SandboxConstants.PROP_SANDBOX_STORE_PREFIX + workflowStoreName),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
String path = workflowStoreName + ":/" + JNDIConstants.DIR_DEFAULT_WWW +
"/" + JNDIConstants.DIR_DEFAULT_APPBASE;
// DNS name mangle the property name - can only contain value DNS characters!
String dnsProp = SandboxConstants.PROP_DNS + DNSNameMangler.MakeDNSName(stagingStore, packageName);
this.avmService.setStoreProperty(workflowStoreName, QName.createQName(null, dnsProp),
new PropertyValue(DataTypeDefinition.TEXT, path));
// the main workflow store depends on the main user store (dist=1)
String prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + userStore;
this.avmService.setStoreProperty(workflowStoreName, QName.createQName(null, prop_key),
new PropertyValue(DataTypeDefinition.INT, 1));
// The main workflow store depends on the main staging store (dist=2)
prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + stagingStore;
this.avmService.setStoreProperty(workflowStoreName, QName.createQName(null, prop_key),
new PropertyValue(DataTypeDefinition.INT, 2));
// snapshot the store
this.avmService.createSnapshot(workflowStoreName, null, null);
// create the workflow 'preview' store
String previewStoreName = workflowStoreName + STORE_SEPARATOR + "preview";
this.avmService.createStore(previewStoreName);
if (logger.isDebugEnabled())
logger.debug("Created user workflow sandbox preview store: " + previewStoreName);
// create a layered directory pointing to 'www' in the workflow 'main' store
this.avmService.createLayeredDirectory(
workflowStoreName + ":/" + JNDIConstants.DIR_DEFAULT_WWW,
previewStoreName + ":/", JNDIConstants.DIR_DEFAULT_WWW);
// tag the store with the store type
this.avmService.setStoreProperty(previewStoreName, SandboxConstants.PROP_SANDBOX_WORKFLOW_PREVIEW,
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with its own store name for querying.
avmService.setStoreProperty(previewStoreName,
QName.createQName(null, SandboxConstants.PROP_SANDBOX_STORE_PREFIX + previewStoreName),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
path = previewStoreName + ":/" + JNDIConstants.DIR_DEFAULT_WWW +
"/" + JNDIConstants.DIR_DEFAULT_APPBASE;
// DNS name mangle the property name - can only contain value DNS characters!
dnsProp = SandboxConstants.PROP_DNS + DNSNameMangler.MakeDNSName(userStore, packageName, "preview");
this.avmService.setStoreProperty(previewStoreName, QName.createQName(null, dnsProp),
new PropertyValue(DataTypeDefinition.TEXT, path));
// The preview worfkflow store depends on the main workflow store (dist=1)
prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + workflowStoreName;
this.avmService.setStoreProperty(previewStoreName, QName.createQName(null, prop_key),
new PropertyValue(DataTypeDefinition.INT, 1));
// The preview workflow store depends on the main user store (dist=2)
prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + userStore;
this.avmService.setStoreProperty(previewStoreName, QName.createQName(null, prop_key),
new PropertyValue(DataTypeDefinition.INT, 2));
// The preview workflow store depends on the main staging store (dist=3)
prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + stagingStore;
this.avmService.setStoreProperty(previewStoreName, QName.createQName(null, prop_key),
new PropertyValue(DataTypeDefinition.INT, 3));
// snapshot the store
this.avmService.createSnapshot(previewStoreName, null, null);
// tag all related stores to indicate that they are part of a single sandbox
QName sandboxIdProp = QName.createQName(SandboxConstants.PROP_SANDBOXID + GUID.generate());
this.avmService.setStoreProperty(workflowStoreName, sandboxIdProp,
new PropertyValue(DataTypeDefinition.TEXT, null));
this.avmService.setStoreProperty(previewStoreName, sandboxIdProp,
new PropertyValue(DataTypeDefinition.TEXT, null));
// return the main workflow store name
return workflowStoreName;
}
/**
* Sets up a workflow package from the given main workflow store and applies
* the list of paths as modified items within the main workflow store.

View File

@@ -24,22 +24,17 @@
*/
package org.alfresco.repo.jscript;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.alfresco.config.JNDIConstants;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.avmsync.AVMDifference;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.NameMatcher;
import org.alfresco.util.ParameterCheck;
import org.alfresco.wcm.sandbox.SandboxService;
import org.alfresco.wcm.util.WCMUtil;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
@@ -53,8 +48,6 @@ public final class AVM extends BaseScopableProcessorExtension
/** Repository Service Registry */
private ServiceRegistry services;
private NameMatcher matcher;
/**
* Set the service registry
*
@@ -65,11 +58,6 @@ public final class AVM extends BaseScopableProcessorExtension
this.services = serviceRegistry;
}
public void setNameMatcher(NameMatcher matcher)
{
this.matcher = matcher;
}
/**
* @return a array of all AVM stores in the system
*/
@@ -163,29 +151,18 @@ public final class AVM extends BaseScopableProcessorExtension
ParameterCheck.mandatoryString("Username", username);
ParameterCheck.mandatoryString("Webapp", webapp);
List<AVMNode> items;
SandboxService sbService = this.services.getSandboxService();
AVMService avmService = this.services.getAVMService();
// get modified items - not including deleted
List<AVMNodeDescriptor> nodes = sbService.listChangedItemsWebApp(storeId, webapp, false);
// build the paths to the stores to compare - filter by current webapp
String userStore = userSandboxStore(storeId, username);
String userStorePath = getStoreRootWebappPath(userStore, webapp);
String stagingStore = stagingStore(storeId);
String stagingStorePath = getStoreRootWebappPath(stagingStore, webapp);
List<AVMNode> items = new ArrayList<AVMNode>(nodes.size());
List<AVMDifference> diffs = this.services.getAVMSyncService().compare(
-1, userStorePath, -1, stagingStorePath, this.matcher);
items = new ArrayList<AVMNode>(diffs.size());
for (AVMDifference diff : diffs)
{
// convert each diff record into an AVM Node template wrapper
String sourcePath = diff.getSourcePath();
AVMNodeDescriptor node = avmService.lookup(-1, sourcePath);
if (node != null)
for (AVMNodeDescriptor node : nodes)
{
// convert each diff/node record into an AVM Node wrapper
items.add(new AVMNode(node.getPath(), -1, this.services, getScope()));
}
}
return items;
}
@@ -197,8 +174,7 @@ public final class AVM extends BaseScopableProcessorExtension
*/
public static String stagingStore(String storeId)
{
ParameterCheck.mandatoryString("Store ID", storeId);
return storeId;
return WCMUtil.buildStagingStoreName(storeId);
}
/**
@@ -209,9 +185,7 @@ public final class AVM extends BaseScopableProcessorExtension
*/
public static String userSandboxStore(String storeId, String username)
{
ParameterCheck.mandatoryString("Store ID", storeId);
ParameterCheck.mandatoryString("Username", username);
return storeId + "--" + username;
return WCMUtil.buildUserMainStoreName(storeId, username);
}
/**
@@ -221,9 +195,7 @@ public final class AVM extends BaseScopableProcessorExtension
*/
public String websiteStagingUrl(String storeId)
{
ParameterCheck.mandatoryString("Store ID", storeId);
return MessageFormat.format(JNDIConstants.PREVIEW_SANDBOX_URL,
lookupStoreDNS(storeId), getVServerDomain(), getVServerPort());
return WCMUtil.buildStoreUrl(this.services.getAVMService(), storeId, getVServerDomain(), getVServerPort());
}
/**
@@ -247,25 +219,7 @@ public final class AVM extends BaseScopableProcessorExtension
*/
public String assetUrl(String store, String assetPath)
{
ParameterCheck.mandatoryString("Store", store);
ParameterCheck.mandatoryString("Asset Path", assetPath);
if (assetPath.startsWith('/' + JNDIConstants.DIR_DEFAULT_WWW +
'/' + JNDIConstants.DIR_DEFAULT_APPBASE))
{
assetPath = assetPath.substring(('/' + JNDIConstants.DIR_DEFAULT_WWW +
'/' + JNDIConstants.DIR_DEFAULT_APPBASE).length());
}
if (assetPath.startsWith("/ROOT"))
{
assetPath = assetPath.substring(("/ROOT").length());
}
if (assetPath.length() == 0 || assetPath.charAt(0) != '/')
{
assetPath = '/' + assetPath;
}
return MessageFormat.format(JNDIConstants.PREVIEW_ASSET_URL,
lookupStoreDNS(store), getVServerDomain(), getVServerPort(), assetPath);
return WCMUtil.buildAssetUrl(assetPath, getVServerDomain(), getVServerPort(), WCMUtil.lookupStoreDNS(this.services.getAVMService(), store));
}
/**
@@ -315,27 +269,6 @@ public final class AVM extends BaseScopableProcessorExtension
*/
public static String getWebappsFolderPath()
{
return '/' + JNDIConstants.DIR_DEFAULT_WWW +
'/' + JNDIConstants.DIR_DEFAULT_APPBASE;
return JNDIConstants.DIR_DEFAULT_WWW_APPBASE;
}
private static String getStoreRootPath(String store)
{
return store + ":" + getWebappsFolderPath();
}
private static String getStoreRootWebappPath(String store, String webapp)
{
return getStoreRootPath(store) + '/' + webapp;
}
private String lookupStoreDNS(String store)
{
Map<QName, PropertyValue> props =
this.services.getAVMService().queryStorePropertyKey(store, QName.createQName(null, PROP_DNS + '%'));
return (props.size() == 1
? props.keySet().iterator().next().getLocalName().substring(PROP_DNS.length()) : null);
}
private final static String PROP_DNS = ".dns.";
}

View File

@@ -69,6 +69,7 @@ import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.wcm.sandbox.SandboxService;
import org.alfresco.wcm.webproject.WebProjectService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
@@ -468,4 +469,11 @@ public class ServiceDescriptorRegistry
public WebProjectService getWebProjectService() {
return (WebProjectService)getService(WEBPROJECT_SERVICE);
}
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getSandboxService()
*/
public SandboxService getSandboxService() {
return (SandboxService)getService(SANDBOX_SERVICE);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
* Copyright (C) 2005-2008 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,21 +24,16 @@
*/
package org.alfresco.repo.template;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.alfresco.config.JNDIConstants;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.avmsync.AVMDifference;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.NameMatcher;
import org.alfresco.util.ParameterCheck;
import org.alfresco.wcm.sandbox.SandboxService;
import org.alfresco.wcm.util.WCMUtil;
/**
* AVM root object access for a template model.
@@ -48,7 +43,6 @@ import org.alfresco.util.ParameterCheck;
public class AVM extends BaseTemplateProcessorExtension
{
private ServiceRegistry services;
private NameMatcher matcher;
/**
* Sets the service registry
@@ -60,11 +54,6 @@ public class AVM extends BaseTemplateProcessorExtension
this.services = services;
}
public void setNameMatcher(NameMatcher matcher)
{
this.matcher = matcher;
}
/**
* @return a list of all AVM stores in the system
*/
@@ -152,29 +141,18 @@ public class AVM extends BaseTemplateProcessorExtension
ParameterCheck.mandatoryString("Username", username);
ParameterCheck.mandatoryString("Webapp", webapp);
List<AVMTemplateNode> items;
SandboxService sbService = this.services.getSandboxService();
AVMService avmService = this.services.getAVMService();
// get modified items - not including deleted
List<AVMNodeDescriptor> nodes = sbService.listChangedItemsWebApp(storeId, webapp, false);
// build the paths to the stores to compare - filter by current webapp
String userStore = userSandboxStore(storeId, username);
String userStorePath = getStoreRootWebappPath(userStore, webapp);
String stagingStore = stagingStore(storeId);
String stagingStorePath = getStoreRootWebappPath(stagingStore, webapp);
List<AVMTemplateNode> items = new ArrayList<AVMTemplateNode>(nodes.size());
List<AVMDifference> diffs = this.services.getAVMSyncService().compare(
-1, userStorePath, -1, stagingStorePath, this.matcher);
items = new ArrayList<AVMTemplateNode>(diffs.size());
for (AVMDifference diff : diffs)
{
// convert each diff record into an AVM Node template wrapper
String sourcePath = diff.getSourcePath();
AVMNodeDescriptor node = avmService.lookup(-1, sourcePath);
if (node != null)
for (AVMNodeDescriptor node : nodes)
{
// convert each diff/node record into an AVM Node template wrapper
items.add(new AVMTemplateNode(node, this.services, getTemplateImageResolver()));
}
}
return items;
}
@@ -186,8 +164,7 @@ public class AVM extends BaseTemplateProcessorExtension
*/
public static String stagingStore(String storeId)
{
ParameterCheck.mandatoryString("Store ID", storeId);
return storeId;
return WCMUtil.buildStagingStoreName(storeId);
}
/**
@@ -198,9 +175,7 @@ public class AVM extends BaseTemplateProcessorExtension
*/
public static String userSandboxStore(String storeId, String username)
{
ParameterCheck.mandatoryString("Store ID", storeId);
ParameterCheck.mandatoryString("Username", username);
return storeId + "--" + username;
return WCMUtil.buildUserMainStoreName(storeId, username);
}
/**
@@ -210,9 +185,7 @@ public class AVM extends BaseTemplateProcessorExtension
*/
public String websiteStagingUrl(String storeId)
{
ParameterCheck.mandatoryString("Store ID", storeId);
return MessageFormat.format(JNDIConstants.PREVIEW_SANDBOX_URL,
lookupStoreDNS(storeId), getVServerDomain(), getVServerPort());
return WCMUtil.buildStoreUrl(this.services.getAVMService(), storeId, getVServerDomain(), getVServerPort());
}
/**
@@ -236,25 +209,7 @@ public class AVM extends BaseTemplateProcessorExtension
*/
public String assetUrl(String store, String assetPath)
{
ParameterCheck.mandatoryString("Store", store);
ParameterCheck.mandatoryString("Asset Path", assetPath);
if (assetPath.startsWith('/' + JNDIConstants.DIR_DEFAULT_WWW +
'/' + JNDIConstants.DIR_DEFAULT_APPBASE))
{
assetPath = assetPath.substring(('/' + JNDIConstants.DIR_DEFAULT_WWW +
'/' + JNDIConstants.DIR_DEFAULT_APPBASE).length());
}
if (assetPath.startsWith("/ROOT"))
{
assetPath = assetPath.substring(("/ROOT").length());
}
if (assetPath.length() == 0 || assetPath.charAt(0) != '/')
{
assetPath = '/' + assetPath;
}
return MessageFormat.format(JNDIConstants.PREVIEW_ASSET_URL,
lookupStoreDNS(store), getVServerDomain(), getVServerPort(), assetPath);
return WCMUtil.buildAssetUrl(assetPath, getVServerDomain(), getVServerPort(), WCMUtil.lookupStoreDNS(this.services.getAVMService(), store));
}
/**
@@ -304,27 +259,6 @@ public class AVM extends BaseTemplateProcessorExtension
*/
public static String getWebappsFolderPath()
{
return '/' + JNDIConstants.DIR_DEFAULT_WWW +
'/' + JNDIConstants.DIR_DEFAULT_APPBASE;
return JNDIConstants.DIR_DEFAULT_WWW_APPBASE;
}
private static String getStoreRootPath(String store)
{
return store + ":" + getWebappsFolderPath();
}
private static String getStoreRootWebappPath(String store, String webapp)
{
return getStoreRootPath(store) + '/' + webapp;
}
private String lookupStoreDNS(String store)
{
Map<QName, PropertyValue> props =
this.services.getAVMService().queryStorePropertyKey(store, QName.createQName(null, PROP_DNS + '%'));
return (props.size() == 1
? props.keySet().iterator().next().getLocalName().substring(PROP_DNS.length()) : null);
}
private final static String PROP_DNS = ".dns.";
}

View File

@@ -33,6 +33,7 @@ import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.attributes.AttributeService;
import org.alfresco.service.cmr.audit.AuditService;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.deploy.DeploymentService;
import org.alfresco.service.cmr.avm.locking.AVMLockingService;
import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
@@ -62,12 +63,12 @@ import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.cmr.view.ExporterService;
import org.alfresco.service.cmr.view.ImporterService;
import org.alfresco.service.cmr.avm.deploy.DeploymentService;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.wcm.sandbox.SandboxService;
import org.alfresco.wcm.webproject.WebProjectService;
@@ -129,6 +130,7 @@ public interface ServiceRegistry
static final QName TAGGING_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "TaggingService");
static final QName DEPLOYMENT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "DeploymentService");
static final QName WEBPROJECT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "WebProjectService");
static final QName SANDBOX_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "SandboxService");
/**
* Get the list of services provided by the Repository
@@ -429,4 +431,11 @@ public interface ServiceRegistry
*/
@NotAuditable
WebProjectService getWebProjectService();
/**
* Get the Sandbox Service
* @return
*/
@NotAuditable
SandboxService getSandboxService();
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2005-2008 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.wcm;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.alfresco.wcm.sandbox.SandboxServiceImplTest;
import org.alfresco.wcm.webproject.WebProjectServiceImplTest;
/**
* WCM test suite
*
* @author janv
*/
public class WCMTestSuite extends TestSuite
{
/**
* Creates the test suite
*
* @return the test suite
*/
public static Test suite()
{
TestSuite suite = new TestSuite();
suite.addTestSuite(WebProjectServiceImplTest.class);
suite.addTestSuite(SandboxServiceImplTest.class);
return suite;
}
}

View File

@@ -43,6 +43,7 @@ public class SandboxConstants
public final static String PROP_DNS = ".dns.";
public final static String PROP_SANDBOX_STORE_PREFIX = ".sandbox.store.";
// sandbox type
public final static QName PROP_SANDBOX_STAGING_MAIN = QName.createQName(null, ".sandbox.staging.main");
public final static QName PROP_SANDBOX_STAGING_PREVIEW = QName.createQName(null, ".sandbox.staging.preview");
public final static QName PROP_SANDBOX_AUTHOR_MAIN = QName.createQName(null, ".sandbox.author.main");
@@ -51,6 +52,7 @@ public class SandboxConstants
public final static QName PROP_SANDBOX_WORKFLOW_PREVIEW = QName.createQName(null, ".sandbox.workflow.preview");
public final static QName PROP_SANDBOX_AUTHOR_WORKFLOW_MAIN = QName.createQName(null, ".sandbox.author.workflow.main");
public final static QName PROP_SANDBOX_AUTHOR_WORKFLOW_PREVIEW = QName.createQName(null, ".sandbox.author.workflow.preview");
public final static QName PROP_WEBSITE_NAME = QName.createQName(null, ".website.name");
public final static QName PROP_AUTHOR_NAME = QName.createQName(null, ".author.name");
public final static QName PROP_WEB_PROJECT_NODE_REF = QName.createQName(null, ".web_project.noderef");

View File

@@ -24,24 +24,29 @@
*/
package org.alfresco.wcm.sandbox;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.alfresco.config.JNDIConstants;
import org.alfresco.model.WCMAppModel;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.mbeans.VirtServerRegistry;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.avm.locking.AVMLockingService;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.DNSNameMangler;
import org.alfresco.util.GUID;
import org.alfresco.util.ParameterCheck;
import org.alfresco.wcm.util.WCMUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -57,9 +62,11 @@ public final class SandboxFactory extends WCMUtil
private static Log logger = LogFactory.getLog(SandboxFactory.class);
/** Services */
private NodeService nodeService;
private PermissionService permissionService;
private AVMService avmService;
private NodeService nodeService;
private AVMLockingService avmLockingService;
private VirtServerRegistry virtServerRegistry;
public void setNodeService(NodeService nodeService)
{
@@ -76,6 +83,17 @@ public final class SandboxFactory extends WCMUtil
this.avmService = avmService;
}
public void setAvmLockingService(AVMLockingService avmLockingService)
{
this.avmLockingService = avmLockingService;
}
public void setVirtServerRegistry(VirtServerRegistry virtServerRegistry)
{
this.virtServerRegistry = virtServerRegistry;
}
/**
* Private constructor
*/
@@ -109,7 +127,7 @@ public final class SandboxFactory extends WCMUtil
if (logger.isDebugEnabled())
{
logger.debug("Created staging sandbox store: " + stagingStoreName);
logger.debug("Created staging sandbox: " + stagingStoreName);
}
// we can either branch from an existing staging store or create a new structure
@@ -200,24 +218,97 @@ public final class SandboxFactory extends WCMUtil
dumpStoreProperties(avmService, previewStoreName);
}
return new SandboxInfo( new String[] { stagingStoreName, previewStoreName } );
return getSandbox(stagingStoreName);
}
protected void setStagingPermissions(String storeId, NodeRef webProjectNodeRef)
/**
* Get sandbox info for given sandbox store id
*
* @param sandboxId
* @return SandboxInfo returns sandbox info or null if sandbox does not exist or is not visible
*/
public SandboxInfo getSandbox(String sandboxId)
{
AVMStoreDescriptor storeDesc = avmService.getStore(sandboxId);
if (storeDesc == null)
{
return null;
}
String wpStoreId = WCMUtil.getWebProjectStoreId(sandboxId);
String[] storeNames = null;
// Check sandbox type
Map<QName, PropertyValue> props = avmService.getStoreProperties(sandboxId);
QName sandboxType = null;
// derive name for now
String name = null;
if (props.containsKey(SandboxConstants.PROP_SANDBOX_STAGING_MAIN))
{
sandboxType = SandboxConstants.PROP_SANDBOX_STAGING_MAIN;
name = sandboxId;
storeNames = new String[] {sandboxId, WCMUtil.getCorrespondingPreviewStoreName(sandboxId)};
}
else if ( props.containsKey( SandboxConstants.PROP_SANDBOX_STAGING_PREVIEW))
{
sandboxType = SandboxConstants.PROP_SANDBOX_STAGING_PREVIEW;
storeNames = new String[] {WCMUtil.getCorrespondingMainStoreName(sandboxId), sandboxId};
}
else if (props.containsKey(SandboxConstants.PROP_SANDBOX_AUTHOR_MAIN))
{
sandboxType = SandboxConstants.PROP_SANDBOX_AUTHOR_MAIN;
name = WCMUtil.getUserName(sandboxId);
storeNames = new String[] {sandboxId, WCMUtil.getCorrespondingPreviewStoreName(sandboxId)};
}
else if (props.containsKey(SandboxConstants.PROP_SANDBOX_AUTHOR_PREVIEW))
{
sandboxType = SandboxConstants.PROP_SANDBOX_AUTHOR_PREVIEW;
name = WCMUtil.getUserName(sandboxId);
storeNames = new String[] {WCMUtil.getCorrespondingMainStoreName(sandboxId), sandboxId};
}
else if (props.containsKey(SandboxConstants.PROP_SANDBOX_WORKFLOW_MAIN))
{
sandboxType = SandboxConstants.PROP_SANDBOX_WORKFLOW_MAIN;
name = WCMUtil.getWorkflowId(sandboxId);
storeNames = new String[] {sandboxId, WCMUtil.getCorrespondingPreviewStoreName(sandboxId)};
}
else if (props.containsKey(SandboxConstants.PROP_SANDBOX_WORKFLOW_PREVIEW))
{
sandboxType = SandboxConstants.PROP_SANDBOX_WORKFLOW_PREVIEW;
name = WCMUtil.getWorkflowId(sandboxId);
storeNames = new String[] {WCMUtil.getCorrespondingMainStoreName(sandboxId), sandboxId};
}
if ((storeNames == null) || (storeNames.length == 0))
{
throw new AlfrescoRuntimeException("Must have at least one store");
}
if ((storeNames.length == 1) && (! sandboxType.equals(SandboxConstants.PROP_SANDBOX_STAGING_MAIN)))
{
throw new AlfrescoRuntimeException("Main store must be of type: " + SandboxConstants.PROP_SANDBOX_STAGING_MAIN);
}
return new SandboxInfoImpl(wpStoreId, sandboxId, sandboxType, name, storeNames, new Date(storeDesc.getCreateDate()), storeDesc.getCreator());
}
protected void setStagingPermissions(String storeId, NodeRef wpNodeRef)
{
String storeName = WCMUtil.buildStagingStoreName(storeId);
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, WCMUtil.buildStoreRootPath(storeName));
// Apply sepcific user permissions as set on the web project
// Apply specific user permissions as set on the web project
// All these will be masked out
List<ChildAssociationRef> userInfoRefs = nodeService.getChildAssocs(
webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
for (ChildAssociationRef ref : userInfoRefs)
Map<String, String> userRoles = WCMUtil.listWebUsers(nodeService, wpNodeRef);
for (Map.Entry<String, String> userRole : userRoles.entrySet())
{
NodeRef userInfoRef = ref.getChildRef();
String username = (String)nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
String userrole = (String)nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
String username = userRole.getKey();
String userrole = userRole.getValue();
permissionService.setPermission(dirRef, username, userrole, true);
}
@@ -238,7 +329,7 @@ public final class SandboxFactory extends WCMUtil
permissionService.setPermission(dirRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true);
}
public void updateStagingAreaManagers(String storeId, NodeRef webProjectNodeRef, final List<String> managers)
private void updateStagingAreaManagers(String storeId, NodeRef webProjectNodeRef, final List<String> managers)
{
// The stores have the mask set in updateSandboxManagers
String storeName = WCMUtil.buildStagingStoreName(storeId);
@@ -256,10 +347,10 @@ public final class SandboxFactory extends WCMUtil
}
}
public void addStagingAreaUser(String storeId, String authority, String role)
public void addStagingAreaUser(String wpStoreId, String authority, String role)
{
// The stores have the mask set in updateSandboxManagers
String storeName = WCMUtil.buildStagingStoreName(storeId);
String storeName = WCMUtil.buildStagingStoreName(wpStoreId);
NodeRef dirRef = AVMNodeConverter.ToNodeRef(-1, WCMUtil.buildStoreRootPath(storeName));
permissionService.setPermission(dirRef, authority, role, true);
@@ -293,20 +384,23 @@ public final class SandboxFactory extends WCMUtil
String userStoreName = WCMUtil.buildUserMainStoreName(storeId, username);
String previewStoreName = WCMUtil.buildUserPreviewStoreName(storeId, username);
if (avmService.getStore(userStoreName) != null)
SandboxInfo userSandboxInfo = getSandbox(userStoreName);
if (userSandboxInfo != null)
{
if (logger.isDebugEnabled())
{
logger.debug("Not creating as store already exists: " + userStoreName);
logger.debug("Not creating author sandbox as it already exists: " + userStoreName);
}
return new SandboxInfo( new String[] { userStoreName, previewStoreName } );
return userSandboxInfo;
}
avmService.createStore(userStoreName);
String stagingStoreName = WCMUtil.buildStagingStoreName(storeId);
if (logger.isDebugEnabled())
logger.debug("Created user sandbox store: " + userStoreName +
" above staging store " + stagingStoreName);
{
logger.debug("Created user sandbox: " + userStoreName + " above staging store " + stagingStoreName);
}
// create a layered directory pointing to 'www' in the staging area
avmService.createLayeredDirectory(WCMUtil.buildStoreRootPath(stagingStoreName),
@@ -417,7 +511,8 @@ public final class SandboxFactory extends WCMUtil
dumpStoreProperties(avmService, userStoreName);
dumpStoreProperties(avmService, previewStoreName);
}
return new SandboxInfo( new String[] { userStoreName, previewStoreName } );
return getSandbox(userStoreName);
}
/**
@@ -533,7 +628,232 @@ public final class SandboxFactory extends WCMUtil
dumpStoreProperties(avmService, mainStoreName);
dumpStoreProperties(avmService, previewStoreName);
}
return new SandboxInfo( new String[] { mainStoreName, previewStoreName } );
return getSandbox(mainStoreName);
}
/**
* Creates a workflow sandbox for the given user store. This will create a
* workflow sandbox layered over the user's main store.
*
* @param stagingStore The name of the staging store the user sandbox is layered over
* @param userStore The name of the user store to create the workflow for
* @return The store name of the main store in the workflow sandbox
*/
// TODO refactor AVMExpiredContentProcessor ...
public String createUserWorkflowSandbox(String stagingStore, String userStore)
{
// create the workflow 'main' store
String packageName = "workflow-" + GUID.generate();
String workflowStoreName = userStore + STORE_SEPARATOR + packageName;
this.avmService.createStore(workflowStoreName);
if (logger.isDebugEnabled())
logger.debug("Created user workflow sandbox store: " + workflowStoreName);
// create a layered directory pointing to 'www' in the users store
this.avmService.createLayeredDirectory(
userStore + ":/" + JNDIConstants.DIR_DEFAULT_WWW,
workflowStoreName + ":/", JNDIConstants.DIR_DEFAULT_WWW);
// tag the store with the store type
this.avmService.setStoreProperty(workflowStoreName,
SandboxConstants.PROP_SANDBOX_AUTHOR_WORKFLOW_MAIN,
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the name of the author's store this one is layered over
this.avmService.setStoreProperty(workflowStoreName,
SandboxConstants.PROP_AUTHOR_NAME,
new PropertyValue(DataTypeDefinition.TEXT, userStore));
// tag the store, oddly enough, with its own store name for querying.
this.avmService.setStoreProperty(workflowStoreName,
QName.createQName(null, SandboxConstants.PROP_SANDBOX_STORE_PREFIX + workflowStoreName),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
String path = workflowStoreName + ":/" + JNDIConstants.DIR_DEFAULT_WWW +
"/" + JNDIConstants.DIR_DEFAULT_APPBASE;
// DNS name mangle the property name - can only contain value DNS characters!
String dnsProp = SandboxConstants.PROP_DNS + DNSNameMangler.MakeDNSName(stagingStore, packageName);
this.avmService.setStoreProperty(workflowStoreName, QName.createQName(null, dnsProp),
new PropertyValue(DataTypeDefinition.TEXT, path));
// the main workflow store depends on the main user store (dist=1)
String prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + userStore;
this.avmService.setStoreProperty(workflowStoreName, QName.createQName(null, prop_key),
new PropertyValue(DataTypeDefinition.INT, 1));
// The main workflow store depends on the main staging store (dist=2)
prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + stagingStore;
this.avmService.setStoreProperty(workflowStoreName, QName.createQName(null, prop_key),
new PropertyValue(DataTypeDefinition.INT, 2));
// snapshot the store
this.avmService.createSnapshot(workflowStoreName, null, null);
// create the workflow 'preview' store
String previewStoreName = workflowStoreName + STORE_SEPARATOR + "preview";
this.avmService.createStore(previewStoreName);
if (logger.isDebugEnabled())
logger.debug("Created user workflow sandbox preview store: " + previewStoreName);
// create a layered directory pointing to 'www' in the workflow 'main' store
this.avmService.createLayeredDirectory(
workflowStoreName + ":/" + JNDIConstants.DIR_DEFAULT_WWW,
previewStoreName + ":/", JNDIConstants.DIR_DEFAULT_WWW);
// tag the store with the store type
this.avmService.setStoreProperty(previewStoreName, SandboxConstants.PROP_SANDBOX_WORKFLOW_PREVIEW,
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with its own store name for querying.
avmService.setStoreProperty(previewStoreName,
QName.createQName(null, SandboxConstants.PROP_SANDBOX_STORE_PREFIX + previewStoreName),
new PropertyValue(DataTypeDefinition.TEXT, null));
// tag the store with the DNS name property
path = previewStoreName + ":/" + JNDIConstants.DIR_DEFAULT_WWW +
"/" + JNDIConstants.DIR_DEFAULT_APPBASE;
// DNS name mangle the property name - can only contain value DNS characters!
dnsProp = SandboxConstants.PROP_DNS + DNSNameMangler.MakeDNSName(userStore, packageName, "preview");
this.avmService.setStoreProperty(previewStoreName, QName.createQName(null, dnsProp),
new PropertyValue(DataTypeDefinition.TEXT, path));
// The preview worfkflow store depends on the main workflow store (dist=1)
prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + workflowStoreName;
this.avmService.setStoreProperty(previewStoreName, QName.createQName(null, prop_key),
new PropertyValue(DataTypeDefinition.INT, 1));
// The preview workflow store depends on the main user store (dist=2)
prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + userStore;
this.avmService.setStoreProperty(previewStoreName, QName.createQName(null, prop_key),
new PropertyValue(DataTypeDefinition.INT, 2));
// The preview workflow store depends on the main staging store (dist=3)
prop_key = SandboxConstants.PROP_BACKGROUND_LAYER + stagingStore;
this.avmService.setStoreProperty(previewStoreName, QName.createQName(null, prop_key),
new PropertyValue(DataTypeDefinition.INT, 3));
// snapshot the store
this.avmService.createSnapshot(previewStoreName, null, null);
// tag all related stores to indicate that they are part of a single sandbox
QName sandboxIdProp = QName.createQName(SandboxConstants.PROP_SANDBOXID + GUID.generate());
this.avmService.setStoreProperty(workflowStoreName, sandboxIdProp,
new PropertyValue(DataTypeDefinition.TEXT, null));
this.avmService.setStoreProperty(previewStoreName, sandboxIdProp,
new PropertyValue(DataTypeDefinition.TEXT, null));
// return the main workflow store name
return workflowStoreName;
}
public List<SandboxInfo> listSandboxes(final String wpStoreId, String userName)
{
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
ParameterCheck.mandatoryString("userName", userName);
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<List<SandboxInfo>>()
{
public List<SandboxInfo> doWork() throws Exception
{
List<AVMStoreDescriptor> stores = avmService.getStores();
List<SandboxInfo> sbInfos = new ArrayList<SandboxInfo>();
for (AVMStoreDescriptor store : stores)
{
String storeName = store.getName();
// list main stores - not preview stores or workflow stores
if ((storeName.startsWith(wpStoreId)) &&
(! WCMUtil.isPreviewStore(storeName)) &&
(! WCMUtil.isWorkflowStore(storeName)))
{
sbInfos.add(getSandbox(storeName));
}
}
return sbInfos;
}
}, userName);
}
public void deleteSandbox(String sbStoreId)
{
SandboxInfo sbInfo = getSandbox(sbStoreId);
if (sbInfo != null)
{
String mainSandboxStore = sbInfo.getMainStoreName();
// found the sandbox to remove - remove the main store (eg. user main store, staging main store, workflow main store)
String path = WCMUtil.buildSandboxRootPath(mainSandboxStore);
// Notify virtualisation server about removing this sandbox.
//
// Implementation note:
//
// Because the removal of virtual webapps in the
// virtualization server is recursive, it only
// needs to be given the name of the main store.
//
// This notification must occur *prior* to purging content
// within the AVM because the virtualization server must list
// the avm_webapps dir in each store to discover which
// virtual webapps must be unloaded. The virtualization
// server traverses the sandbox's stores in most-to-least
// dependent order, so clients don't have to worry about
// accessing a preview layer whose main layer has been torn
// out from under it.
WCMUtil.removeAllVServerWebapps(virtServerRegistry, path, true);
// TODO: Use the .sandbox-id. property to delete all sandboxes,
// rather than assume a sandbox always had a single preview
// layer attached.
// purge stores, eg. main store followed by preview store
String[] avmStoreNames = sbInfo.getStoreNames();
for (String avmStoreName : avmStoreNames)
{
// check it exists before we try to remove it
if (avmService.getStore(avmStoreName) != null)
{
// purge store from the system
avmService.purgeStore(avmStoreName);
}
// remove any locks this user may have
avmLockingService.removeStoreLocks(avmStoreName);
}
}
}
public void updateSandboxManagers(final String wpStoreId, NodeRef wpNodeRef, List<String> managers)
{
// walk existing user sandboxes and reapply manager permissions to include new manager user
List<SandboxInfo> sbInfos = AuthenticationUtil.runAs(new RunAsWork<List<SandboxInfo>>()
{
public List<SandboxInfo> doWork() throws Exception
{
return listSandboxes(wpStoreId, AuthenticationUtil.getSystemUserName());
}
}, AuthenticationUtil.getSystemUserName());
for (SandboxInfo sbInfo : sbInfos)
{
if (sbInfo.getSandboxType().equals(SandboxConstants.PROP_SANDBOX_AUTHOR_MAIN))
{
String username = sbInfo.getName();
updateUserSandboxManagers(wpStoreId, managers, username);
}
}
updateStagingAreaManagers(wpStoreId, wpNodeRef, managers);
}
/**
@@ -545,7 +865,7 @@ public final class SandboxFactory extends WCMUtil
* @param managers The list of authorities who have ContentManager role in the web project
* @param username Username of the user sandbox to update
*/
public void updateSandboxManagers(final String storeId, final List<String> managers, final String username)
private void updateUserSandboxManagers(final String storeId, final List<String> managers, final String username)
{
final String userStoreName = WCMUtil.buildUserMainStoreName(storeId, username);
final String previewStoreName = WCMUtil.buildUserPreviewStoreName(storeId, username);

View File

@@ -24,23 +24,43 @@
*/
package org.alfresco.wcm.sandbox;
import java.io.Serializable;
import java.util.Date;
import org.alfresco.service.namespace.QName;
/**
* Provides information about a WCM sandbox created by SandboxFactory.
*/
public final class SandboxInfo implements Serializable
public interface SandboxInfo
{
private static final long serialVersionUID = 3615436375385857404L;
String [] store_names_;
public SandboxInfo(String [] store_names)
{
store_names_ = store_names;
}
/**
* Get the name
*
* @return String name
*/
public String getName();
/**
* A list of names of the stores within this sandbox.
* The sandbox store id
*/
public String getSandboxId();
/**
* The web project store id
*/
public String getWebProjectId();
/**
* The sandbox type ... for now a QName, based on existing SandboxConstants
*/
public QName getSandboxType();
public Date getCreatedDate();
public String getCreator();
/**
* A list of ids of the stores within this sandbox.
* The "main" store should come first in this list;
* any other stores should appear in the order that
* they are overlaid on "main" (e.g.: any "preview"
@@ -48,10 +68,10 @@ public final class SandboxInfo implements Serializable
* <p>
* Note: all sandboxes must have a "main" layer.
*/
public String [] getStoreNames() { return store_names_; }
public String[] getStoreNames();
/**
* The name of the "main" store within this sandbox.
* The id of the "main" store within this sandbox.
*/
public String getMainStoreName() { return store_names_[0]; }
public String getMainStoreName();
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2005-2008 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.wcm.sandbox;
import java.util.Date;
import org.alfresco.service.namespace.QName;
/**
* Provides information about a WCM sandbox created by Sandbox Service/Factory
*/
public class SandboxInfoImpl implements SandboxInfo
{
private String wpStoreId;
private String sbStoreId;
private QName sandboxType;
private String name;
private String[] storeNames;
private Date createdDate;
private String creator;
/* package */ SandboxInfoImpl(String wpStoreId, String sbStoreId, QName sandboxType, String name, String[] storeNames, Date createdDate, String creator)
{
this.wpStoreId = wpStoreId;
this.sbStoreId = sbStoreId;
this.sandboxType = sandboxType;
this.name = name;
this.storeNames = storeNames;
this.createdDate = createdDate;
this.creator = creator;
}
// note: currently derived - for author sandbox this is the username, for staging sandbox this is the sandbox id
public String getName()
{
return this.name;
}
public String getWebProjectId()
{
return this.wpStoreId;
}
public String getSandboxId()
{
return this.sbStoreId;
}
public QName getSandboxType()
{
return this.sandboxType;
}
public Date getCreatedDate()
{
return this.createdDate;
}
public String getCreator()
{
return this.creator;
}
/**
* A list of names of the stores within this sandbox.
* The "main" store should come first in this list;
* any other stores should appear in the order that
* they are overlaid on "main" (e.g.: any "preview"
* layers should come afterward, in "lowest first" order).
* <p>
* Note: all sandboxes must have a "main" layer.
*/
public String [] getStoreNames() { return storeNames; }
/**
* The name of the "main" store within this sandbox.
*/
public String getMainStoreName()
{
return storeNames[0];
}
}

View File

@@ -0,0 +1,308 @@
/*
* Copyright (C) 2005-2008 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.wcm.sandbox;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.VersionDescriptor;
import org.alfresco.service.namespace.QName;
/**
* Sandbox Service fundamental API.
* <p>
* This service API is designed to support the public facing Sandbox APIs.
*
* @author janv
*/
public interface SandboxService
{
/**
* Create author/user sandbox within a web project for the current user
* <p>
* If the author sandbox already exists for this web project then it will be returned
*
* @param wpStoreId web project store id
* @return SandboxInfo the created user sandbox info
*/
public SandboxInfo createAuthorSandbox(String wpStoreId);
/**
* Create author/user sandbox within a web project for the given user
* <p>
* If the author sandbox already exists for this web project then it will be returned
* <p>
* Current user must be a content manager for the web project
*
* @param wpStoreId web project store id
* @param userName user name
* @return SandboxInfo the created user sandbox info
*/
public SandboxInfo createAuthorSandbox(String wpStoreId, String userName);
/**
* List the available sandboxes for the current user and given web project
*
* @param wpStoreId web project store id
* @return List<SandboxInfo> list of sandbox info
*/
public List<SandboxInfo> listSandboxes(String wpStoreId);
/**
* List the available sandboxes for the given user and web project
* <p>
* Current user must be a content manager for the web project
*
* @param wpStoreId web project store id
* @param userName user name
* @return List<SandboxInfo> list of sandbox info
*/
public List<SandboxInfo> listSandboxes(String wpStoreId, String userName);
/**
* Return true if sandbox is visible to user and is of given type
* <p>
* eg. isSandboxType("test123--myusername", SandboxConstants.PROP_SANDBOX_AUTHOR_MAIN)
*
* @param sbStoreId sandbox store id
* @param sandboxType sandbox type (see SandboxConstants)
* @return boolean true, if sandbox exists with given type
*/
public boolean isSandboxType(String sbStoreId, QName sandboxType);
/**
* Get sandbox info
*
* @param sbStoreId sandbox store id
* @return SandboxInfo null if sandbox does not exist or is not visible to the current user
*/
public SandboxInfo getSandbox(String sbStoreId);
/**
* Gets author/user sandbox info for the current user
* <p>
* Returns null if the author sandbox can not be found
*
* @param wpStoreId web project store id
* @return SandboxInfo author sandbox info
*/
public SandboxInfo getAuthorSandbox(String wpStoreId);
/**
* Gets author/user sandbox info for the given user
* <p>
* Returns null if the user sandbox can not be found
* <p>
* Current user must be a content manager for the web project
*
* @param wpStoreId web project store id
* @param userName userName
* @return SandboxInfo author sandbox info
*/
public SandboxInfo getAuthorSandbox(String wpStoreId, String userName);
/**
* Gets staging sandbox info
* <p>
* Returns null if the staging sandbox can not be found
*
* @param wpStoreId web project store id
* @return SandboxInfo staging sandbox info
*/
public SandboxInfo getStagingSandbox(String wpStoreId);
/**
* Delete the sandbox
* <p>
* If the sandbox does not exist, will log a warning and succeed
* <p>
* Current user must be a content manager for the web project (associated with the sandbox)
*
* @param sbStoreId sandbox store id
*/
public void deleteSandbox(String sbStoreId);
/**
* List changed items for given sandbox (eg. for user sandbox compared to staging sandbox)
* <p>
* Note: This will list new/modified/deleted items from the root directory and below, including all web apps
*
* @param sbStoreId sandbox store id
* @param includeDeleted if true, include deleted items as well as new/modified items
* @return List<AVMNodeDescriptor> list of changed items
*/
public List<AVMNodeDescriptor> listChangedItems(String sbStoreId, boolean includeDeleted);
/**
* List changed items for given sandbox and web app (eg. in user sandbox)
* <p>
* Note: This will list new/modified/deleted items for the given web app
*
* @param sbStoreId sandbox store id
* @param webApp web app to filter by
* @param includeDeleted if true, include deleted items as well as new/modified items
* @return List<AVMNodeDescriptor> list of changed items
*/
public List<AVMNodeDescriptor> listChangedItemsWebApp(String sbStoreId, String webApp, boolean includeDeleted);
/**
* List changed items for given sandbox path (eg. between user sandbox and staging sandbox)
* <p>
* Note: This will list new/modified/deleted items from the directory and below. The destination path will be dervied.
*
* @param avmSrcPath source sandbox path (an AVM path)
* @param includeDeleted if true, include deleted items as well as new/modified items
* @return List<AVMNodeDescriptor> list of changed items
*/
public List<AVMNodeDescriptor> listChangedItemsDir(String avmSrcPath, boolean includeDeleted);
/**
* List changed (new/modified/deleted) items between any two sandbox paths
*
* @param avmSrcPath source sandbox path (an AVM path)
* @param avmDstPath destination sandbox path (an AVM path)
* @param includeDeleted if true, include deleted items as well as new/modified items
* @return List<AVMNodeDescriptor> list of changed items
*/
public List<AVMNodeDescriptor> listChangedItems(String avmSrcPath, String avmDstPath, boolean includeDeleted);
/**
* Submit all changed items for given sandbox (eg. from user sandbox to staging sandbox)
* <p>
* Note: This will submit new/modified/deleted items from the root directory and below, including all web apps
* <p>
* @param sbStoreId sandbox store id
*/
public void submitAll(String sbStoreId, String submitLabel, String submitComment);
/**
* Submit all changed items for given sandbox and web app (eg. in user sandbox)
* <p>
* Note: This will submit new/modified/deleted items for the given web app
*
* @param sbStoreId sandbox store id
* @param webApp web app to filter by
*/
public void submitAllWebApp(String sbStoreId, String webApp, String submitLabel, String submitComment);
/**
* Submit all changed items for given sandbox path (eg. in user sandbox)
* <p>
* Note: This will submit new/modified/deleted items from the directory and below
*
* @param avmDirectoryPath path to filter by
*/
public void submitAllDir(String avmDirectoryPath, String submitLabel, String submitComment);
/**
* Submit list of changed items for given sandbox (eg. from user sandbox to staging sandbox)
*
* @param sbStoreId sandbox store id
* @param items list of AVM node descriptors
*/
public void submitList(String sbStoreId, List<AVMNodeDescriptor> items, String submitLabel, String submitComment);
/**
* Submit list of changed items for given sandbox (eg. from user sandbox to staging sandbox)
*
* @param sbStoreId sandbox store id
* @param items list of AVM node descriptors
* @param expirationDates map of <path, date> for those items set with an expiration date, or can be null (if no expiration dates)
*/
public void submitList(String sbStoreId, List<AVMNodeDescriptor> items, Map<String, Date> expirationDates, final String submitLabel, final String submitComment);
/**
* Revert all changed items for given sandbox (eg. in user sandbox)
* <p>
* Note: This will revert new/modified/deleted items from the root directory and below, including all web apps
*
* @param sbStoreId sandbox store id
*/
public void revertAll(String sbStoreId);
/**
* Revert all changed items for given sandbox and web app (eg. in user sandbox)
* <p>
* Note: This will revert new/modified/deleted items for the given web app
*
* @param sbStoreId sandbox store id
* @param webApp web app to filter by
*/
public void revertAllWebApp(String sbStoreId, String webApp);
/**
* Revert all changed items for given sandbox path (eg. in user sandbox)
* <p>
* Note: This will revert new/modified/deleted items from the directory and below
*
* @param avmDirectoryPath path to filter by
*/
public void revertAllDir(String avmDirectoryPath);
/**
* Revert list of changed items for given sandbox (eg. in user sandbox)
*
* @param items list of AVM node descriptors
*/
public void revertList(String sbStoreId, List<AVMNodeDescriptor> items);
/**
* Revert sandbox to a specific snapshot version ID (ie. for staging sandbox)
* <p>
* Current user must be a content manager for the web project
*
* @param sbStoreId staging sandbox store id
* @param version version
*/
public void revertSnapshot(String sbStoreId, int version);
/**
* List all snapshots (sandbox versions) for the given sandbox (ie. for staging sandbox)
* <p>
* Current user must be a content manager for the web project
*
* @param sbStoreId staging sandbox store id
* @param includeSystemGenerated if false will ignore system generated snapshots else true to get all snapshots
* @return List<VersionDescriptor> list of AVM version descriptors
*/
public List<VersionDescriptor> listSnapshots(String sbStoreId, boolean includeSystemGenerated);
/**
* List snapshots (sandbox versions) for the given sandbox between given dates (ie. for staging sandbox)
* <p>
* Current user must be a content manager for the web project
*
* @param sbStoreId staging sandbox store id
* @param from from date
* @param to to date
* @param includeSystemGenerated if false will ignore system generated snapshots else true to get all snapshots
* @return List<VersionDescriptor> list of AVM version descriptors
*/
public List<VersionDescriptor> listSnapshots(String sbStoreId, Date from, Date to, boolean includeSystemGenerated);
}

View File

@@ -0,0 +1,858 @@
/*
* Copyright (C) 2005-2008 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.wcm.sandbox;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.mbeans.VirtServerRegistry;
import org.alfresco.model.WCMAppModel;
import org.alfresco.repo.avm.AVMDAOs;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.avm.actions.AVMRevertStoreAction;
import org.alfresco.repo.avm.actions.AVMUndoSandboxListAction;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionListenerAdapter;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.VersionDescriptor;
import org.alfresco.service.cmr.avm.locking.AVMLockingService;
import org.alfresco.service.cmr.avmsync.AVMDifference;
import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.NameMatcher;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.VirtServerUtils;
import org.alfresco.wcm.util.WCMUtil;
import org.alfresco.wcm.util.WCMWorkflowUtil;
import org.alfresco.wcm.webproject.WebProjectInfo;
import org.alfresco.wcm.webproject.WebProjectService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Sandbox Service fundamental API.
* <p>
* This service API is designed to support the public facing Sandbox APIs.
*
* @author janv
*/
public class SandboxServiceImpl extends WCMUtil implements SandboxService
{
/** Logger */
private static Log logger = LogFactory.getLog(SandboxServiceImpl.class);
private WebProjectService wpService;
private SandboxFactory sandboxFactory;
private AVMService avmService;
private AVMLockingService avmLockingService;
private AVMSyncService avmSyncService;
private NameMatcher nameMatcher;
private VirtServerRegistry virtServerRegistry;
private ActionService actionService;
private WorkflowService workflowService;
public void setWebProjectService(WebProjectService wpService)
{
this.wpService = wpService;
}
public void setSandboxFactory(SandboxFactory sandboxFactory)
{
this.sandboxFactory = sandboxFactory;
}
public void setAvmService(AVMService avmService)
{
this.avmService = avmService;
}
public void setAvmLockingService(AVMLockingService avmLockingService)
{
this.avmLockingService = avmLockingService;
}
public void setAvmSyncService(AVMSyncService avmSyncService)
{
this.avmSyncService = avmSyncService;
}
public void setNameMatcher(NameMatcher nameMatcher)
{
this.nameMatcher = nameMatcher;
}
public void setVirtServerRegistry(VirtServerRegistry virtServerRegistry)
{
this.virtServerRegistry = virtServerRegistry;
}
public void setActionService(ActionService actionService)
{
this.actionService = actionService;
}
public void setWorkflowService(WorkflowService workflowService)
{
this.workflowService = workflowService;
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#createAuthorSandbox(java.lang.String)
*/
public SandboxInfo createAuthorSandbox(String wpStoreId)
{
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
String currentUserName = AuthenticationUtil.getCurrentEffectiveUserName();
SandboxInfo sbInfo = null;
if (! wpService.isWebUser(wpStoreId, currentUserName))
{
throw new AccessDeniedException("Only web project users may create their own (author) sandbox for '"+currentUserName+"' (store id: "+wpStoreId+")");
}
else
{
sbInfo = createAuthorSandboxImpl(wpStoreId, currentUserName);
}
return sbInfo;
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#createAuthorSandbox(java.lang.String, java.lang.String)
*/
public SandboxInfo createAuthorSandbox(String wpStoreId, String userName)
{
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
ParameterCheck.mandatoryString("userName", userName);
// is the current user a content manager for this web project ?
if (! wpService.isContentManager(wpStoreId))
{
throw new AccessDeniedException("Only content managers may create author sandbox for '"+userName+"' (store id: "+wpStoreId+")");
}
return createAuthorSandboxImpl(wpStoreId, userName);
}
private SandboxInfo createAuthorSandboxImpl(String wpStoreId, String userName)
{
WebProjectInfo wpInfo = wpService.getWebProject(wpStoreId);
final NodeRef wpNodeRef = wpInfo.getNodeRef();
final List<String> managers = new ArrayList<String>(4);
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork() throws Exception
{
// retrieve the list of managers from the existing users
Map<String, String> existingUserRoles = wpService.listWebUsers(wpNodeRef);
for (Map.Entry<String, String> userRole : existingUserRoles.entrySet())
{
String username = userRole.getKey();
String userrole = userRole.getValue();
if (WCMUtil.ROLE_CONTENT_MANAGER.equals(userrole) && managers.contains(username) == false)
{
managers.add(username);
}
}
return null;
}
}, AuthenticationUtil.getSystemUserName());
String role = wpService.getWebUserRole(wpNodeRef, userName);
SandboxInfo sbInfo = sandboxFactory.createUserSandbox(wpStoreId, managers, userName, role);
List<SandboxInfo> sandboxInfoList = new LinkedList<SandboxInfo>();
sandboxInfoList.add(sbInfo);
// Bind the post-commit transaction listener with data required for virtualization server notification
CreateSandboxTransactionListener tl = new CreateSandboxTransactionListener(sandboxInfoList, wpService.listWebApps(wpNodeRef));
AlfrescoTransactionSupport.bindListener(tl);
if (logger.isInfoEnabled())
{
logger.info("Created author sandbox: " + sbInfo.getSandboxId() + " (web project id: " + wpStoreId + ")");
}
return sbInfo;
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#listSandboxes(java.lang.String)
*/
public List<SandboxInfo> listSandboxes(String wpStoreId)
{
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
return sandboxFactory.listSandboxes(wpStoreId, AuthenticationUtil.getCurrentEffectiveUserName());
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#listSandboxes(java.lang.String, java.lang.String)
*/
public List<SandboxInfo> listSandboxes(final String wpStoreId, String userName)
{
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
ParameterCheck.mandatoryString("userName", userName);
if (! wpService.isContentManager(wpStoreId))
{
throw new AccessDeniedException("Only content managers may list sandboxes for '"+userName+"' (web project id: "+wpStoreId+")");
}
return sandboxFactory.listSandboxes(wpStoreId, userName);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#isSandboxType(java.lang.String, org.alfresco.service.namespace.QName)
*/
public boolean isSandboxType(String sbStoreId, QName sandboxType)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
ParameterCheck.mandatory("sandboxType", sandboxType);
SandboxInfo sbInfo = sandboxFactory.getSandbox(sbStoreId);
if (sbInfo != null)
{
return sbInfo.getSandboxType().equals(sandboxType);
}
return false;
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#getSandbox(java.lang.String)
*/
public SandboxInfo getSandbox(String sbStoreId)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
return sandboxFactory.getSandbox(sbStoreId);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#getAuthorSandbox(java.lang.String)
*/
public SandboxInfo getAuthorSandbox(String wpStoreId)
{
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
String currentUserName = AuthenticationUtil.getCurrentEffectiveUserName();
return getSandbox(WCMUtil.buildUserMainStoreName(WCMUtil.buildStagingStoreName(wpStoreId), currentUserName));
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#getUserSandbox(java.lang.String, java.lang.String)
*/
public SandboxInfo getAuthorSandbox(String wpStoreId, String userName)
{
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
ParameterCheck.mandatoryString("userName", userName);
if (! wpService.isContentManager(wpStoreId))
{
throw new AccessDeniedException("Only content managers may get author sandbox for '"+userName+"' (web project id: "+wpStoreId+")");
}
return getSandbox(WCMUtil.buildUserMainStoreName(WCMUtil.buildStagingStoreName(wpStoreId), userName));
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#getStagingSandbox(java.lang.String)
*/
public SandboxInfo getStagingSandbox(String wpStoreId)
{
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
return getSandbox(WCMUtil.buildStagingStoreName(wpStoreId));
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#deleteSandbox(java.lang.String)
*/
public void deleteSandbox(String sbStoreId)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
String wpStoreId = WCMUtil.getWebProjectStoreId(sbStoreId);
String currentUserName = AuthenticationUtil.getCurrentEffectiveUserName();
if (sbStoreId.equals(WCMUtil.buildUserMainStoreName(wpStoreId, currentUserName)))
{
// author may delete their own sandbox
sandboxFactory.deleteSandbox(sbStoreId);
}
else
{
if (! wpService.isContentManager(wpStoreId))
{
throw new AccessDeniedException("Only content managers may delete sandbox '"+sbStoreId+"' (web project id: "+wpStoreId+")");
}
if (sbStoreId.equals(wpStoreId))
{
throw new AlfrescoRuntimeException("Cannot delete staging sandbox '"+sbStoreId+"' (web project id: "+wpStoreId+")");
}
// content manager may delete sandboxes, except staging sandbox
sandboxFactory.deleteSandbox(sbStoreId);
}
if (logger.isInfoEnabled())
{
logger.info("Deleted sandbox: " + sbStoreId + " (web project id: " + wpStoreId + ")");
}
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#listChangedItems(java.lang.String, boolean)
*/
public List<AVMNodeDescriptor> listChangedItems(String sbStoreId, boolean includeDeleted)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
// no filtering
String avmDirectoryPath = sbStoreId+":/";
return listChangedItemsDir(avmDirectoryPath, includeDeleted);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#listChangedItemsWebApp(java.lang.String, java.lang.String, boolean)
*/
public List<AVMNodeDescriptor> listChangedItemsWebApp(String sbStoreId, String webApp, boolean includeDeleted)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
ParameterCheck.mandatoryString("webApp", webApp);
// filter by current webapp
String avmDirectoryPath = WCMUtil.buildStoreWebappPath(sbStoreId, webApp);
return listChangedItemsDir(avmDirectoryPath, includeDeleted);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#listChangedItemsDir(java.lang.String, boolean)
*/
public List<AVMNodeDescriptor> listChangedItemsDir(String avmDirectoryPath, boolean includeDeleted)
{
ParameterCheck.mandatoryString("avmDirectoryPath", avmDirectoryPath);
String sandboxId = WCMUtil.getSandboxStoreId(avmDirectoryPath);
// TODO - allow list for any sandbox
if (! WCMUtil.isUserStore(sandboxId))
{
throw new AlfrescoRuntimeException("Not an author sandbox: "+sandboxId);
}
// build the paths to the stores to compare - filter by given directory path
String wpStoreId = WCMUtil.getWebProjectStoreId(sandboxId);
String stagingSandboxId = WCMUtil.buildStagingStoreName(wpStoreId);
String relativePath = WCMUtil.getStoreRelativePath(avmDirectoryPath);
String srcPath = sandboxId + AVM_STORE_SEPARATOR + relativePath;
String dstPath = stagingSandboxId + AVM_STORE_SEPARATOR + relativePath;
return listChangedItems(srcPath, dstPath, includeDeleted);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#listChangedItems(java.lang.String, java.lang.String, boolean)
*/
public List<AVMNodeDescriptor> listChangedItems(String avmSrcPath, String avmDstPath, boolean includeDeleted)
{
return listChangedItems(-1, avmSrcPath, -1, avmDstPath, includeDeleted);
}
private List<AVMNodeDescriptor> listChangedItems(int srcVersion, String srcPath, int dstVersion, String dstPath, boolean includeDeleted)
{
ParameterCheck.mandatoryString("srcPath", srcPath);
ParameterCheck.mandatoryString("dstPath", dstPath);
long start = System.currentTimeMillis();
List<AVMDifference> diffs = avmSyncService.compare(srcVersion, srcPath, dstVersion, dstPath, nameMatcher);
List<AVMNodeDescriptor> items = new ArrayList<AVMNodeDescriptor>(diffs.size());
for (AVMDifference diff : diffs)
{
// convert each diff record into an AVM node descriptor
String sourcePath = diff.getSourcePath();
AVMNodeDescriptor node = avmService.lookup(-1, sourcePath, includeDeleted);
if (node != null)
{
items.add(node);
}
}
if (logger.isTraceEnabled())
{
logger.trace("listModifiedItems: "+items.size()+" items in "+(System.currentTimeMillis()-start)+" ms (between "+srcVersion+","+srcPath+" and "+dstVersion+","+dstPath);
}
return items;
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#submitAll(java.lang.String, java.lang.String, java.lang.String)
*/
public void submitAll(String sbStoreId, String submitLabel, String submitComment)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
String avmDirectoryPath = sbStoreId+":/";
submitAllDir(avmDirectoryPath, submitLabel, submitComment);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#submitAllWebApp(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
*/
public void submitAllWebApp(String sbStoreId, String webApp, String submitLabel, String submitComment)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
ParameterCheck.mandatoryString("webApp", webApp);
String avmDirectoryPath = WCMUtil.buildStoreWebappPath(sbStoreId, webApp);
submitAllDir(avmDirectoryPath, submitLabel, submitComment);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#submitAllDir(java.lang.String, java.lang.String, java.lang.String)
*/
public void submitAllDir(String avmDirectoryPath, String submitLabel, String submitComment)
{
ParameterCheck.mandatoryString("avmDirectoryPath", avmDirectoryPath);
String sbStoreId = WCMUtil.getSandboxStoreId(avmDirectoryPath);
List<AVMNodeDescriptor> items = listChangedItemsDir(avmDirectoryPath, true);
submitList(sbStoreId, items, submitLabel, submitComment);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#submitList(java.lang.String, java.util.List, java.lang.String, java.lang.String)
*/
public void submitList(String sbStoreId, List<AVMNodeDescriptor> items, final String submitLabel, final String submitComment)
{
submitList(sbStoreId, items, null, submitLabel, submitComment);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#submitList(java.lang.String, java.util.List, java.util.Map, java.lang.String, java.lang.String)
*/
public void submitList(String sbStoreId, List<AVMNodeDescriptor> items, Map<String, Date> expirationDates, final String submitLabel, final String submitComment)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
// direct submit to the staging area (without workflow)
// TODO - consider submit to higher-level sandbox, not just to staging
if (! WCMUtil.isUserStore(sbStoreId))
{
throw new AlfrescoRuntimeException("Not an author sandbox: "+sbStoreId);
}
// construct diffs for selected items for submission
String wpStoreId = WCMUtil.getWebProjectStoreId(sbStoreId);
String stagingSandboxId = WCMUtil.buildStagingStoreName(wpStoreId);
final List<AVMDifference> diffs = new ArrayList<AVMDifference>(items.size());
for (AVMNodeDescriptor item : items)
{
String relativePath = WCMUtil.getStoreRelativePath(item.getPath());
String srcPath = sbStoreId + AVM_STORE_SEPARATOR + relativePath;
String dstPath = stagingSandboxId + AVM_STORE_SEPARATOR + relativePath;
AVMDifference diff = new AVMDifference(-1, srcPath, -1, dstPath, AVMDifference.NEWER);
diffs.add(diff);
if (expirationDates != null)
{
// process the expiration date (if any)
processExpirationDate(srcPath, expirationDates);
}
// recursively remove locks from this item
recursivelyRemoveLocks(wpStoreId, -1, avmService.lookup(-1, srcPath, true), srcPath);
// check to see if destPath forces a notification of the virtualization server
// (e.g.: it might be a path to a jar file within WEB-INF/lib).
if (VirtServerUtils.requiresUpdateNotification(dstPath))
{
// Bind the post-commit transaction listener with data required for virtualization server notification
UpdateSandboxTransactionListener tl = new UpdateSandboxTransactionListener(dstPath);
AlfrescoTransactionSupport.bindListener(tl);
}
}
// write changes to layer so files are marked as modified
// Submit is done as system as the staging store is read only
// We could add support to runIgnoringStoreACls
// TODO review flatten - assumes webapps, hence currently flattens at /www/avm_webapps level
// also review flatten for SimpleAVMSubmitAction and AVMSubmitAction
final String sandboxPath = WCMUtil.buildSandboxRootPath(sbStoreId);
final String stagingPath = WCMUtil.buildSandboxRootPath(stagingSandboxId);
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork() throws Exception
{
avmSyncService.update(diffs, null, true, true, false, false, submitLabel, submitComment);
AVMDAOs.Instance().fAVMNodeDAO.flush();
avmSyncService.flatten(sandboxPath, stagingPath);
return null;
}
}, AuthenticationUtil.getSystemUserName());
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#revertAll(java.lang.String, java.lang.String)
*/
public void revertAll(String sbStoreId)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
String avmDirectoryPath = sbStoreId+":/";
revertAllDir(avmDirectoryPath);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#revertAll(java.lang.String, java.lang.String)
*/
public void revertAllWebApp(String sbStoreId, String webApp)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
ParameterCheck.mandatoryString("webApp", webApp);
String avmDirectoryPath = WCMUtil.buildStoreWebappPath(sbStoreId, webApp);
revertAllDir(avmDirectoryPath);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#revertAll(java.lang.String)
*/
public void revertAllDir(String avmDirectoryPath)
{
ParameterCheck.mandatoryString("avmDirectoryPath", avmDirectoryPath);
String sbStoreId = WCMUtil.getSandboxStoreId(avmDirectoryPath);
List<AVMNodeDescriptor> items = listChangedItemsDir(avmDirectoryPath, true);
revertList(sbStoreId, items);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#revertList(java.lang.String, java.lang.String, java.util.List)
*/
public void revertList(String sbStoreId, List<AVMNodeDescriptor> items)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
List<Pair<Integer, String>> versionPaths = new ArrayList<Pair<Integer, String>>(items.size());
List<WorkflowTask> tasks = null;
for (AVMNodeDescriptor node : items)
{
if (tasks == null)
{
tasks = WCMWorkflowUtil.getAssociatedTasksForSandbox(workflowService, WCMUtil.getSandboxStoreId(node.getPath()));
}
if (WCMWorkflowUtil.getAssociatedTasksForNode(avmService, node, tasks).size() == 0)
{
String revertPath = node.getPath();
versionPaths.add(new Pair<Integer, String>(-1, revertPath));
if (VirtServerUtils.requiresUpdateNotification(revertPath))
{
// Bind the post-commit transaction listener with data required for virtualization server notification
UpdateSandboxTransactionListener tl = new UpdateSandboxTransactionListener(revertPath);
AlfrescoTransactionSupport.bindListener(tl);
}
}
}
Map<String, Serializable> args = new HashMap<String, Serializable>(1, 1.0f);
args.put(AVMUndoSandboxListAction.PARAM_NODE_LIST, (Serializable)versionPaths);
Action action = actionService.createAction(AVMUndoSandboxListAction.NAME, args);
actionService.executeAction(action, null); // dummy action ref, list passed as action arg
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#listSnapshots(java.lang.String, boolean)
*/
public List<VersionDescriptor> listSnapshots(String sbStoreId, boolean includeSystemGenerated)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
String wpStoreId = WCMUtil.getWebProjectStoreId(sbStoreId);
if (! wpService.isContentManager(wpStoreId))
{
throw new AccessDeniedException("Only content managers may list snapshots '"+sbStoreId+"' (web project id: "+wpStoreId+")");
}
List<VersionDescriptor> allVersions = avmService.getStoreVersions(sbStoreId);
return listSnapshots(allVersions, includeSystemGenerated);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#listSnapshots(java.lang.String, java.util.Date, java.util.Date, boolean)
*/
public List<VersionDescriptor> listSnapshots(String sbStoreId, Date from, Date to, boolean includeSystemGenerated)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
String wpStoreId = WCMUtil.getWebProjectStoreId(sbStoreId);
if (! wpService.isContentManager(wpStoreId))
{
throw new AccessDeniedException("Only content managers may list snapshots '"+sbStoreId+"' (web project id: "+wpStoreId+")");
}
List<VersionDescriptor> versionsToFilter = avmService.getStoreVersions(sbStoreId, from, to);
return listSnapshots(versionsToFilter, includeSystemGenerated);
}
private List<VersionDescriptor> listSnapshots(List<VersionDescriptor> versionsToFilter, boolean includeSystemGenerated)
{
List<VersionDescriptor> versions = new ArrayList<VersionDescriptor>(versionsToFilter.size());
for (int i = versionsToFilter.size() - 1; i >= 0; i--) // reverse order
{
VersionDescriptor item = versionsToFilter.get(i);
// only display snapshots with a valid tag - others are system generated snapshots
if ((includeSystemGenerated == true) || ((item.getTag() != null) && (item.getVersionID() != 0)))
{
versions.add(item);
}
}
return versions;
}
/* (non-Javadoc)
* @see org.alfresco.wcm.sandbox.SandboxService#revertSnapshot(java.lang.String, int)
*/
public void revertSnapshot(final String sbStoreId, final int version)
{
ParameterCheck.mandatoryString("sbStoreId", sbStoreId);
String wpStoreId = WCMUtil.getWebProjectStoreId(sbStoreId);
if (! wpService.isContentManager(wpStoreId))
{
throw new AccessDeniedException("Only content managers may revert staging sandbox '"+sbStoreId+"' (web project id: "+wpStoreId+")");
}
// do this as system as the staging area has restricted access (and content manager may not have permission to delete children, for example)
List<AVMDifference> diffs = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<List<AVMDifference>>()
{
public List<AVMDifference> doWork() throws Exception
{
String sandboxPath = WCMUtil.buildSandboxRootPath(sbStoreId);
List<AVMDifference> diffs = avmSyncService.compare(-1, sandboxPath, version, sandboxPath, null);
Map<String, Serializable> args = new HashMap<String, Serializable>(1, 1.0f);
args.put(AVMRevertStoreAction.PARAM_VERSION, version);
Action action = actionService.createAction(AVMRevertStoreAction.NAME, args);
actionService.executeAction(action, AVMNodeConverter.ToNodeRef(-1, sbStoreId + AVM_STORE_SEPARATOR + "/"));
return diffs;
}
}, AuthenticationUtil.getSystemUserName());
// See if any of the files being reverted require notification of the virt server, to update the webapp
for (AVMDifference diff : diffs)
{
if (VirtServerUtils.requiresUpdateNotification(diff.getSourcePath()))
{
// Bind the post-commit transaction listener with data required for virtualization server notification
UpdateSandboxTransactionListener tl = new UpdateSandboxTransactionListener(diff.getSourcePath());
AlfrescoTransactionSupport.bindListener(tl);
break;
}
}
}
/**
* Sets up the expiration date for the given source path
*
* @param srcPath The path to set the expiration date for
*/
private void processExpirationDate(String srcPath, Map<String, Date> expirationDates)
{
// if an expiration date has been set for this item we need to
// add the expires aspect and the date supplied
Date expirationDate = expirationDates.get(srcPath);
if (expirationDate == null)
{
return;
}
// make sure the aspect is present
if (avmService.hasAspect(-1, srcPath, WCMAppModel.ASPECT_EXPIRES) == false)
{
avmService.addAspect(srcPath, WCMAppModel.ASPECT_EXPIRES);
}
// set the expiration date
avmService.setNodeProperty(srcPath, WCMAppModel.PROP_EXPIRATIONDATE,
new PropertyValue(DataTypeDefinition.DATETIME, expirationDate));
if (logger.isDebugEnabled())
{
logger.debug("Set expiration date of " + expirationDate + " for " + srcPath);
}
}
/**
* Recursively remove locks from a path. Walking child folders looking for files
* to remove locks from.
*/
private void recursivelyRemoveLocks(String wpStoreId, int version, AVMNodeDescriptor desc, String absoluteAVMPath)
{
if (desc.isFile() || desc.isDeletedFile())
{
avmLockingService.removeLock(wpStoreId, WCMUtil.getStoreRelativePath(absoluteAVMPath));
}
else
{
if (desc.isDeletedDirectory())
{
// lookup the previous child and get its contents
final List<AVMNodeDescriptor> history = avmService.getHistory(desc, 2);
if (history.size() <= 1)
{
return;
}
desc = history.get(1);
}
Map<String, AVMNodeDescriptor> list = avmService.getDirectoryListingDirect(desc, true);
for (Map.Entry<String, AVMNodeDescriptor> child : list.entrySet())
{
String name = child.getKey();
AVMNodeDescriptor childDesc = child.getValue();
recursivelyRemoveLocks(wpStoreId, version, childDesc, absoluteAVMPath + "/" + name);
}
}
}
/**
* Create Sandbox Transaction listener - invoked after commit
*/
private class CreateSandboxTransactionListener extends TransactionListenerAdapter
{
private List<SandboxInfo> sandboxInfoList;
private List<String> webAppNames;
public CreateSandboxTransactionListener(List<SandboxInfo> sandboxInfoList, List<String> webAppNames)
{
this.sandboxInfoList = sandboxInfoList;
this.webAppNames = webAppNames;
}
/**
* @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
*/
@Override
public void afterCommit()
{
// Handle notification to the virtualization server
// (this needs to occur after the sandboxes are created in the main txn)
// reload virtualisation server for webapp(s) in this web project
for (SandboxInfo sandboxInfo : this.sandboxInfoList)
{
String newlyInvitedStoreName = WCMUtil.buildStagingStoreName(sandboxInfo.getMainStoreName());
for (String webAppName : webAppNames)
{
String path = WCMUtil.buildStoreWebappPath(newlyInvitedStoreName, webAppName);
WCMUtil.updateVServerWebapp(virtServerRegistry, path, true);
}
}
}
}
/**
* Update Sandbox Transaction listener - invoked after submit or revert
*/
private class UpdateSandboxTransactionListener extends TransactionListenerAdapter
{
private String virtUpdatePath;
public UpdateSandboxTransactionListener(String virtUpdatePath)
{
this.virtUpdatePath = virtUpdatePath;
}
/**
* @see org.alfresco.repo.transaction.TransactionListenerAdapter#afterCommit()
*/
@Override
public void afterCommit()
{
// The virtualization server might need to be notified
// because one or more of the files submitted / reverted could alter
// the behavior the virtual webapp in the target of the submit.
// For example, the user might be submitting a new jar or web.xml file.
//
// This must take place after the transaction has been completed;
// force an update of the virt server if necessary
if (this.virtUpdatePath != null)
{
WCMUtil.updateVServerWebapp(virtServerRegistry, this.virtUpdatePath, true);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,116 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.wcm.sandbox.script;
import java.util.Date;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.util.ISO8601DateFormat;
/**
* Asset in a sandbox exposed over Java Script API.
* @author mrogers
*
*/
public class Asset
{
private AVMNodeDescriptor desc;
private Sandbox sandbox;
public Asset(Sandbox sandbox, AVMNodeDescriptor desc)
{
this.sandbox = sandbox;
this.desc = desc;
}
public String getCreator()
{
return desc.getCreator();
}
public Date getCreatedDate()
{
return new Date(desc.getCreateDate());
}
public String getCreatedDateAsISO8601()
{
return ISO8601DateFormat.format(getCreatedDate());
}
public String getModifier()
{
return desc.getLastModifier();
}
public Date getModifiedDate()
{
return new Date(desc.getModDate());
}
public String getModifiedDateAsISO8601()
{
return ISO8601DateFormat.format(getModifiedDate());
}
public String getAssetRef()
{
return desc.getGuid();
}
public String getName()
{
return desc.getName();
}
public String getPath()
{
return desc.getPath();
}
public boolean isFile()
{
return desc.isFile();
}
public boolean isDirectory()
{
return desc.isDirectory();
}
public boolean isDeleted()
{
return desc.isDeleted();
}
/**
* Get the parent sandbox which contains this asset
* @return the parent sandbox which contains this asset
*/
public Sandbox getSandbox()
{
return this.sandbox;
}
}

View File

@@ -0,0 +1,232 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.wcm.sandbox.script;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.alfresco.repo.jscript.ScriptableHashMap;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.util.ISO8601DateFormat;
import org.alfresco.wcm.sandbox.SandboxInfo;
import org.alfresco.wcm.sandbox.SandboxService;
import org.alfresco.wcm.webproject.script.WebProject;
/**
* Sandbox object to expose via JavaScript
* @author mrogers
*
*/
public class Sandbox implements Serializable
{
/**
* serial version id
*/
private static final long serialVersionUID = -9176488061624800911L;
private SandboxInfo si;
private WebProject webproject;
/*
* Constructor from a SandboxInfo
*/
public Sandbox(WebProject webproject, SandboxInfo si)
{
this.webproject = webproject;
this.si = si;
}
public void setName(String name)
{
// read only
}
/**
* Display name for the sandbox
* @return the name of the sandbox
*/
public String getName()
{
return si.getName();
}
/**
* Set the unique reference for this sandbox - no-op, read only
* @param sandboxRef
*/
public void setSandboxRef(String sandboxRef)
{
// read only
}
/**
* Submit the modified contents of this sandbox
*/
public void submitAll(String submitLabel, String submitComment)
{
getSandboxService().submitAll(getSandboxRef(), submitLabel, submitComment);
}
/**
* Submit the modified contents of the webapp within this sandbox
*/
public void submitAllWebApp(String webApp, String submitLabel, String submitComment)
{
getSandboxService().submitAllWebApp(getSandboxRef(), webApp, submitLabel, submitComment);
}
/**
* Revert all modified contents within this sandbox
*/
public void revertAll()
{
getSandboxService().revertAll(getSandboxRef());
}
/**
* Revert all modified contents within this sandbox
*/
public void revertAllWebApp(String webApp)
{
getSandboxService().revertAllWebApp(getSandboxRef(), webApp);
}
/**
* Get the snapshots
* @param includeSystemGenerated
*/
public void getSnapshots(boolean includeSystemGenerated)
{
getSandboxService().listSnapshots(getSandboxRef(), includeSystemGenerated);
}
/**
* Get the unique reference for this sandbox
*/
public String getSandboxRef()
{
return si.getSandboxId();
}
public String getCreator()
{
return si.getCreator();
}
public Date getCreatedDate()
{
return si.getCreatedDate();
}
public String getCreatedDateAsISO8601()
{
return ISO8601DateFormat.format(si.getCreatedDate());
}
/**
* Delete this sandbox
*/
public void deleteSandbox()
{
getSandboxService().deleteSandbox(getSandboxRef());
}
/*
* Save the updates to this sandbox
*/
public void save()
{
// no read-write params yet ...
}
/**
* Get the store names
* @return the list of store names with the "main" store first.
*/
public String[] getStoreNames()
{
return si.getStoreNames();
}
/**
* Get the modified assets within this sandbox
* @return the list of changed assets
*/
public List<Asset> getModifiedAssets()
{
List<AVMNodeDescriptor> items = getSandboxService().listChangedItems(getSandboxRef(), true);
ArrayList<Asset> ret = new ArrayList<Asset>(items.size());
for(AVMNodeDescriptor item : items)
{
Asset a = new Asset(this, item);
ret.add(a);
}
return ret;
}
/**
* Get the modified assets within this sandbox
* @return the list of changed assets
*/
public List<Asset> getModifiedAssetsWebApp(String webApp)
{
List<AVMNodeDescriptor> items = getSandboxService().listChangedItems(getSandboxRef(), webApp, true);
ArrayList<Asset> ret = new ArrayList<Asset>(items.size());
for(AVMNodeDescriptor item : items)
{
Asset a = new Asset(this, item);
ret.add(a);
}
return ret;
}
/**
* Submit a list of files
*/
public void submitList(List<String> toSubmit, String submitLabel, String submitComment)
{
// TODO - Interface will add string list
//ss.submitList(sbStoreId, items, submitLabel, submitComment)
}
public List<Asset> getAssets(String path)
{
return null;
}
public WebProject getWebproject()
{
return this.webproject;
}
private SandboxService getSandboxService()
{
return webproject.getWebProjects().getSandboxService();
}
}

View File

@@ -25,15 +25,22 @@
package org.alfresco.wcm.util;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.alfresco.config.JNDIConstants;
import org.alfresco.mbeans.VirtServerRegistry;
import org.alfresco.model.WCMAppModel;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.VirtServerUtils;
import org.alfresco.wcm.sandbox.SandboxConstants;
@@ -50,15 +57,15 @@ import org.alfresco.wcm.sandbox.SandboxConstants;
public class WCMUtil
{
/**
* Extracts the store name from the avm path
* Extracts the sandbox store id from the avm path
*
* @param avmPath an absolute avm path
*
* @return the store name
* @return the sandbox store id
*/
protected static String getStoreName(final String avmPath)
protected static String getSandboxStoreId(final String avmPath)
{
final int i = avmPath.indexOf(':');
final int i = avmPath.indexOf(AVM_STORE_SEPARATOR);
if (i == -1)
{
throw new IllegalArgumentException("path " + avmPath + " does not contain a store");
@@ -78,7 +85,7 @@ public class WCMUtil
*
* @return the web project store id
*/
protected static String getStoreId(final String storeName)
protected static String getWebProjectStoreId(final String storeName)
{
final int index = storeName.indexOf(WCMUtil.STORE_SEPARATOR);
return (index == -1
@@ -87,17 +94,17 @@ public class WCMUtil
}
/**
* Extracts the store id from the avm path
* Extracts the web project store id from the avm path
*
* For example, if the avm path is: teststore--admin:/www/ROOT then the store id is: teststore
* For example, if the avm path is: teststore--admin:/www/ROOT then the web project id is: teststore
*
* @param avmPath an absolute avm path
*
* @return the store id.
* @return the web project store id.
*/
protected static String getStoreIdFromPath(final String avmPath)
protected static String getWebProjectStoreIdFromPath(final String avmPath)
{
return getStoreId(getStoreName(avmPath));
return getWebProjectStoreId(getSandboxStoreId(avmPath));
}
/**
@@ -109,7 +116,7 @@ public class WCMUtil
*/
protected static boolean isPreviewStore(final String storeName)
{
return storeName.endsWith(WCMUtil.STORE_SEPARATOR + WCMUtil.STORE_PREVIEW);
return ((storeName != null) && (storeName.endsWith(WCMUtil.STORE_SEPARATOR + WCMUtil.STORE_PREVIEW)));
}
/**
@@ -126,7 +133,7 @@ public class WCMUtil
storeName = WCMUtil.getCorrespondingMainStoreName(storeName);
}
return storeName.indexOf(STORE_SEPARATOR + STORE_WORKFLOW) != -1;
return ((storeName != null) && (storeName.indexOf(STORE_SEPARATOR + STORE_WORKFLOW) != -1));
}
/**
@@ -142,19 +149,19 @@ public class WCMUtil
{
storeName = WCMUtil.getCorrespondingMainStoreName(storeName);
}
return storeName.indexOf(WCMUtil.STORE_SEPARATOR) != -1;
return ((storeName != null) && (storeName.indexOf(WCMUtil.STORE_SEPARATOR) != -1));
}
/**
* Indicates whether the store name describes a main store.
* Indicates whether the store name describes a staging store.
*
* @param storeName the store name
*
* @return <tt>true</tt> if the store is a main store, <tt>false</tt> otherwise.
*/
protected static boolean isMainStore(String storeName)
protected static boolean isStagingStore(String storeName)
{
return (storeName.indexOf(WCMUtil.STORE_SEPARATOR) == -1);
return ((storeName != null) && (storeName.indexOf(WCMUtil.STORE_SEPARATOR) == -1));
}
/**
@@ -164,7 +171,7 @@ public class WCMUtil
*
* @return the username associated or <tt>null</tt> if this is a staging store.
*/
protected static String getUserName(String storeName)
public static String getUserName(String storeName)
{
if (WCMUtil.isPreviewStore(storeName))
{
@@ -176,6 +183,24 @@ public class WCMUtil
: storeName.substring(index + WCMUtil.STORE_SEPARATOR.length()));
}
/**
* Extracts the workflow id
*
* @param storeName
* @return
*/
public static String getWorkflowId(String storeName)
{
if (WCMUtil.isPreviewStore(storeName))
{
storeName = WCMUtil.getCorrespondingMainStoreName(storeName);
}
final int index = storeName.indexOf(STORE_SEPARATOR + STORE_WORKFLOW);
return (index == -1
? null
: storeName.substring(index + WCMUtil.STORE_SEPARATOR.length()));
}
/**
* Returns the corresponding main store name if this is a preview store name.
*
@@ -226,7 +251,7 @@ public class WCMUtil
*/
protected static String getCorrespondingPathInMainStore(final String avmPath)
{
String storeName = WCMUtil.getStoreName(avmPath);
String storeName = WCMUtil.getSandboxStoreId(avmPath);
storeName = WCMUtil.getCorrespondingMainStoreName(storeName);
return WCMUtil.getCorrespondingPath(avmPath, storeName);
}
@@ -243,7 +268,7 @@ public class WCMUtil
*/
protected static String getCorrespondingPathInPreviewStore(final String avmPath)
{
String storeName = WCMUtil.getStoreName(avmPath);
String storeName = WCMUtil.getSandboxStoreId(avmPath);
storeName = WCMUtil.getCorrespondingPreviewStoreName(storeName);
return WCMUtil.getCorrespondingPath(avmPath, storeName);
}
@@ -258,20 +283,19 @@ public class WCMUtil
*/
protected static String getCorrespondingPath(final String avmPath, final String otherStore)
{
return (otherStore + ':' + WCMUtil.getStoreRelativePath(avmPath));
return (otherStore + AVM_STORE_SEPARATOR + WCMUtil.getStoreRelativePath(avmPath));
}
/**
* Returns the main staging store name for the specified store id.
* Returns the main staging store name for the specified web project
*
* @param storeId store id to build staging store name for
*
* @return main staging store name for the specified store id
* @param wpStoreId web project store id to build staging store name for
* @return String main staging store name for the specified web project store id
*/
protected static String buildStagingStoreName(final String storeId)
public static String buildStagingStoreName(final String wpStoreId)
{
ParameterCheck.mandatoryString("storeId", storeId);
return storeId;
ParameterCheck.mandatoryString("wpStoreId", wpStoreId);
return wpStoreId;
}
/**
@@ -295,7 +319,7 @@ public class WCMUtil
*
* @return the main store for the specified user and store id
*/
protected static String buildUserMainStoreName(final String storeId,
public static String buildUserMainStoreName(final String storeId,
final String userName)
{
ParameterCheck.mandatoryString("userName", userName);
@@ -361,7 +385,7 @@ public class WCMUtil
protected static String buildStoreRootPath(final String storeName)
{
ParameterCheck.mandatoryString("storeName", storeName);
return storeName + ":/" + JNDIConstants.DIR_DEFAULT_WWW;
return storeName + AVM_STORE_SEPARATOR + "/" + JNDIConstants.DIR_DEFAULT_WWW;
}
/**
@@ -376,7 +400,7 @@ public class WCMUtil
protected static String buildSandboxRootPath(final String storeName)
{
ParameterCheck.mandatoryString("storeName", storeName);
return storeName + ":/" + JNDIConstants.DIR_DEFAULT_WWW_APPBASE;
return storeName + AVM_STORE_SEPARATOR + JNDIConstants.DIR_DEFAULT_WWW_APPBASE;
}
/**
@@ -393,9 +417,7 @@ public class WCMUtil
return WCMUtil.buildSandboxRootPath(storeName) + '/' + webApp;
}
// TODO refactor ...
// assume for now that it is a store name rather than a path - eg. main rather than main:/
protected static String buildStoreUrl(AVMService avmService, String storeName, String domain, String port)
public static String buildStoreUrl(AVMService avmService, String storeName, String domain, String port)
{
ParameterCheck.mandatoryString("storeName", storeName);
@@ -418,7 +440,7 @@ public class WCMUtil
: buildStoreUrl(avmService, storeName, domain, port) + '/' + webApp);
}
protected static String buildAssetUrl(String assetPath, String domain, String port, String dns)
public static String buildAssetUrl(String assetPath, String domain, String port, String dns)
{
ParameterCheck.mandatoryString("assetPath", assetPath);
@@ -443,7 +465,7 @@ public class WCMUtil
return MessageFormat.format(JNDIConstants.PREVIEW_ASSET_URL, dns, domain, port, assetPath);
}
protected static String lookupStoreDNS(AVMService avmService, String store)
public static String lookupStoreDNS(AVMService avmService, String store)
{
ParameterCheck.mandatoryString("store", store);
@@ -502,8 +524,8 @@ public class WCMUtil
*/
protected static String getStoreRelativePath(final String absoluteAVMPath)
{
final Matcher m = STORE_RELATIVE_PATH_PATTERN.matcher(absoluteAVMPath);
return m.matches() && m.group(1).length() != 0 ? m.group(1) : null;
ParameterCheck.mandatoryString("absoluteAVMPath", absoluteAVMPath);
return absoluteAVMPath.substring(absoluteAVMPath.indexOf(AVM_STORE_SEPARATOR) + 1);
}
/**
@@ -571,6 +593,24 @@ public class WCMUtil
return m.matches() && m.group(1).length() != 0 ? m.group(1) : null;
}
protected static Map<String, String> listWebUsers(NodeService nodeService, NodeRef wpNodeRef)
{
List<ChildAssociationRef> userInfoRefs = nodeService.getChildAssocs(wpNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
Map<String, String> webUsers = new HashMap<String, String>(23);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
String userName = (String)nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
String userRole = (String)nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
webUsers.put(userName, userRole);
}
return webUsers;
}
/**
* Creates all directories for a path if they do not already exist.
*/
@@ -685,6 +725,8 @@ public class WCMUtil
// Component Separator.
protected static final String STORE_SEPARATOR = "--";
protected static final char AVM_STORE_SEPARATOR = ':';
// names of the stores representing the layers for an AVM website
//XXXarielb this should be private
protected final static String STORE_WORKFLOW = "workflow";
@@ -702,10 +744,6 @@ public class WCMUtil
public static final String ROLE_CONTENT_REVIEWER = "ContentReviewer";
public static final String ROLE_CONTENT_CONTRIBUTOR = "ContentContributor";
// pattern for absolute AVM Path
private final static Pattern STORE_RELATIVE_PATH_PATTERN =
Pattern.compile("[^:]+:(.+)");
private final static Pattern WEBAPP_RELATIVE_PATH_PATTERN =
Pattern.compile("([^:]+:/" + JNDIConstants.DIR_DEFAULT_WWW +
"/" + JNDIConstants.DIR_DEFAULT_APPBASE + "/([^/]+))(.*)");

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2005-2008 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
package org.alfresco.wcm.util;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.alfresco.model.WCMWorkflowModel;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMNotFoundException;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.LayeringDescriptor;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.service.cmr.workflow.WorkflowTask;
import org.alfresco.service.cmr.workflow.WorkflowTaskQuery;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* WCM Specific workflow related helper methods.
*
* @author Ariel Backenroth
* @author Kevin Roast
* @author janv
*/
public class WCMWorkflowUtil
{
private static final Log logger = LogFactory.getLog(WCMWorkflowUtil.class);
public static List<WorkflowTask> getAssociatedTasksForSandbox(WorkflowService workflowService, final String storeName)
{
String fromPath = WCMUtil.buildStoreRootPath(storeName);
WorkflowTaskQuery query = new WorkflowTaskQuery();
HashMap<QName, Object> props = new HashMap<QName, Object>(1, 1.0f);
props.put(WCMWorkflowModel.PROP_FROM_PATH, fromPath);
query.setProcessCustomProps(props);
query.setActive(true);
List<WorkflowTask> tasks = workflowService.queryTasks(query);
if (logger.isDebugEnabled())
{
logger.debug("found " + tasks.size() + " tasks originating user sandbox " + fromPath);
}
return tasks;
}
public static List<WorkflowTask> getAssociatedTasksForNode(AVMService avmService, AVMNodeDescriptor node, List<WorkflowTask> tasks)
{
List<WorkflowTask> result = new LinkedList<WorkflowTask>();
for (WorkflowTask task : tasks)
{
final NodeRef ref = task.path.instance.workflowPackage;
final String path = WCMUtil.getCorrespondingPath(node.getPath(), ref.getStoreRef().getIdentifier());
if (logger.isDebugEnabled())
{
logger.debug("checking store " + ref.getStoreRef().getIdentifier() +
" for " + node.getPath() + " (" + path + ")");
}
try
{
final LayeringDescriptor ld = avmService.getLayeringInfo(-1, path);
if (!ld.isBackground())
{
if (logger.isDebugEnabled())
{
logger.debug(path + " is in the foreground. workflow active");
}
result.add(task);
}
}
catch (final AVMNotFoundException avmnfe)
{
if (logger.isDebugEnabled())
{
logger.debug(path + " not found");
}
}
}
return result;
}
public static List<WorkflowTask> getAssociatedTasksForNode(WorkflowService workflowService, AVMService avmService, AVMNodeDescriptor node)
{
final List<WorkflowTask> tasks = WCMWorkflowUtil.getAssociatedTasksForSandbox(workflowService, WCMUtil.getSandboxStoreId(node.getPath()));
return getAssociatedTasksForNode(avmService, node, tasks);
}
}

View File

@@ -32,7 +32,7 @@ import org.alfresco.wcm.util.WCMUtil;
*
* @author janv
*/
public class WebProjectInfoImpl extends WCMUtil implements WebProjectInfo
public class WebProjectInfoImpl implements WebProjectInfo
{
/** Web Project node reference */
private NodeRef nodeRef;

View File

@@ -347,12 +347,25 @@ public interface WebProjectService
* Invite users/groups to web project
* <p>
* Note: authority name can be user or group, although a group is flattened into a set of users
* <p>
* Note: author sandbox will NOT be auto created for each invited user
*
* @param wpStoreId web project store id
* @param userGroupRoles map of <authority name, role name> pairs
*/
public void inviteWebUsersGroups(String wpStoreId, Map<String, String> userGroupRoles);
/**
* Invite users/groups to web project
* <p>
* Note: authority name can be user or group, although a group is flattened into a set of users
*
* @param wpStoreId web project store id
* @param userGroupRoles map of <authority name, role name> pairs
* @param autoCreateAuthorSandbox if <tt>true</tt> then auto create an author sandbox for each invited user
*/
public void inviteWebUsersGroups(String wpStoreId, Map<String, String> userGroupRoles, boolean autoCreateAuthorSandbox);
/**
* Invite users/groups to web project
* <p>
@@ -360,11 +373,14 @@ public interface WebProjectService
*
* @param wpNodeRef web project node ref
* @param userGroupRoles map of <authority name, role name> pairs
* @param autoCreateAuthorSandbox if <tt>true</tt> then auto create the author sandbox for each invited user
*/
public void inviteWebUsersGroups(NodeRef wpNodeRef, Map<String, String> userGroupRoles);
public void inviteWebUsersGroups(NodeRef wpNodeRef, Map<String, String> userGroupRoles, boolean autoCreateAuthorSandbox);
/**
* Invite user to web project
* <p>
* Note: author sandbox will NOT be auto created for each invited user
*
* @param wpStoreId web project store id
* @param userName user name (not a group)
@@ -372,19 +388,30 @@ public interface WebProjectService
*/
public void inviteWebUser(String wpStoreId, String userName, String userRole);
/**
* Invite user to web project
*
* @param wpStoreId web project store id
* @param userName user name (not a group)
* @param userRole web project role
* @param autoCreateAuthorSandbox if <tt>true</tt> then auto create the author sandbox for each invited user
*/
public void inviteWebUser(String wpStoreId, String userName, String userRole, boolean autoCreateAuthorSandbox);
/**
* Invite user to web project
*
* @param wpNodeRef web project node ref
* @param userName user name (not a group)
* @param userRole web project role
* @param autoCreateAuthorSandbox if <tt>true</tt> then auto create the author sandbox for each invited user
*/
public void inviteWebUser(NodeRef wpNodeRef, String userName, String userRole);
public void inviteWebUser(NodeRef wpNodeRef, String userName, String userRole, boolean autoCreateAuthorSandbox);
/**
* Uninvite user from a web project
* <p>
* Note: this will cascade delete the user's sandboxes without warning (even if there are modified items)
* Note: author sandbox will NOT be auto deleted
*
* @param wpStoreId web project store id
* @param userName user name
@@ -394,10 +421,22 @@ public interface WebProjectService
/**
* Uninvite user from a web project
* <p>
* Note: this will cascade delete the user's sandboxes without warning (even if there are modified items)
* Note: if author sandbox is auto deleted then this will cascade delete without warning (even if there are changed items)
*
* @param wpStoreId web project store id
* @param userName user name
* @param autoDeleteAuthorSandbox if <tt>true</tt> then auto delete the author sandbox
*/
public void uninviteWebUser(String wpStoreId, String userName, boolean autoDeleteAuthorSandbox);
/**
* Uninvite user from a web project
* <p>
* Note: if author sandbox is auto deleted then this will cascade delete without warning (even if there are changed items)
*
* @param wpNodeRef web project node ref
* @param userName user name
* @param autoDeleteAuthorSandbox if <tt>true</tt> then auto delete the author sandbox
*/
public void uninviteWebUser(NodeRef wpNodeRef, String userName);
public void uninviteWebUser(NodeRef wpNodeRef, String userName, boolean autoDeleteAuthorSandbox);
}

View File

@@ -53,8 +53,8 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthorityService;
@@ -220,7 +220,7 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
// create the AVM staging store to represent the newly created location website
sandboxFactory.createStagingSandbox(wpStoreId, wpNodeRef, branchStoreId); // ignore return
sandboxFactory.createStagingSandbox(wpStoreId, wpNodeRef, branchStoreId); // ignore return, fails if web project already exists
// create the default webapp folder under the hidden system folders
if (branchStoreId == null)
@@ -246,7 +246,9 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
// break the permissions inheritance on the web project node so that only assigned users can access it
permissionService.setInheritParentPermissions(wpNodeRef, false);
inviteWebUser(wpNodeRef, AuthenticationUtil.getCurrentEffectiveUserName(), WCMUtil.ROLE_CONTENT_MANAGER);
// TODO: Currently auto-creates author sandbox for creator of web project (eg. an admin or a DM contributor to web projects root space)
// NOTE: JSF client does not yet allow explicit creation of author sandboxes
inviteWebUser(wpNodeRef, AuthenticationUtil.getCurrentEffectiveUserName(), WCMUtil.ROLE_CONTENT_MANAGER, true);
// Bind the post-commit transaction listener with data required for virtualization server notification
CreateWebProjectTransactionListener tl = new CreateWebProjectTransactionListener(wpStoreId);
@@ -624,27 +626,19 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
WCMUtil.removeAllVServerWebapps(virtServerRegistry, path, true);
// get the list of users who have a sandbox in the website
final Map<String, String> existingUserRoles = listWebUsers(wpNodeRef);
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork() throws Exception
{
for (Map.Entry<String, String> userRole : existingUserRoles.entrySet())
List<SandboxInfo> sbInfos = sandboxFactory.listSandboxes(wpStoreId, AuthenticationUtil.getSystemUserName());
for (SandboxInfo sbInfo : sbInfos)
{
String username = userRole.getKey();
// delete the preview store for this user
deleteStore(WCMUtil.buildUserPreviewStoreName(wpStoreId, username));
// delete the main store for this user
deleteStore(WCMUtil.buildUserMainStoreName(wpStoreId, username));
// delete sandbox
sandboxFactory.deleteSandbox(sbInfo.getSandboxId());
}
// remove the main staging and preview stores
deleteStore(WCMUtil.buildStagingPreviewStoreName(wpStoreId));
deleteStore(WCMUtil.buildStagingStoreName(wpStoreId));
// TODO delete workflow sandboxes !
// delete the web project node itself
nodeService.deleteNode(wpNodeRef);
@@ -660,20 +654,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
}
/**
* Delete a store, checking for its existence first.
*
* @param store
*/
private void deleteStore(final String store)
{
// check it exists before we try to remove it
if (avmService.getStore(store) != null)
{
avmService.purgeStore(store);
}
}
/* (non-Javadoc)
* @see org.alfresco.wcm.webproject.WebProjectService#isContentManager(java.lang.String)
*/
@@ -687,7 +667,7 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
*/
public boolean isContentManager(String storeName, String userName)
{
String wpStoreId = WCMUtil.getStoreId(storeName);
String wpStoreId = WCMUtil.getWebProjectStoreId(storeName);
PropertyValue pValue = avmService.getStoreProperty(wpStoreId, SandboxConstants.PROP_WEB_PROJECT_NODE_REF);
if (pValue != null)
@@ -723,7 +703,7 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
*/
public boolean isWebUser(String storeName, String username)
{
String wpStoreId = WCMUtil.getStoreId(storeName);
String wpStoreId = WCMUtil.getWebProjectStoreId(storeName);
PropertyValue pValue = avmService.getStoreProperty(wpStoreId, SandboxConstants.PROP_WEB_PROJECT_NODE_REF);
if (pValue != null)
@@ -742,7 +722,7 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
*/
public boolean isWebUser(NodeRef wpNodeRef, String userName)
{
String userRole = getWebUserRole(wpNodeRef, userName);
String userRole = getWebUserRoleImpl(wpNodeRef, userName);
return (userRole != null);
}
@@ -751,7 +731,7 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
*/
public int getWebUserCount(NodeRef wpNodeRef)
{
return listWebUserRefs(wpNodeRef).size();
return WCMUtil.listWebUsers(nodeService, wpNodeRef).size();
}
/* (non-Javadoc)
@@ -767,22 +747,10 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
*/
public Map<String, String> listWebUsers(NodeRef wpNodeRef)
{
if (isContentManager(wpNodeRef))
// special case: allow System - eg. to allow user to create their own sandbox on-demand (createAuthorSandbox)
if (isContentManager(wpNodeRef) || (AuthenticationUtil.getCurrentEffectiveUserName().equals(AuthenticationUtil.getSystemUserName())))
{
List<ChildAssociationRef> userInfoRefs = listWebUserRefs(wpNodeRef);
Map<String, String> webUsers = new HashMap<String, String>(23);
for (ChildAssociationRef ref : userInfoRefs)
{
NodeRef userInfoRef = ref.getChildRef();
String userName = (String)nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME);
String userRole = (String)nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE);
webUsers.put(userName, userRole);
}
return webUsers;
return WCMUtil.listWebUsers(nodeService, wpNodeRef);
}
else
{
@@ -790,11 +758,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
}
private List<ChildAssociationRef> listWebUserRefs(NodeRef wpNodeRef)
{
return nodeService.getChildAssocs(wpNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.webproject.WebProjectService#getWebUserRole(java.lang.String, java.lang.String)
*/
@@ -808,7 +771,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
*/
public String getWebUserRole(NodeRef wpNodeRef, String userName)
{
long start = System.currentTimeMillis();
String userRole = null;
if (! isWebProject(wpNodeRef))
@@ -824,6 +786,17 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
else
{
userRole = getWebUserRoleImpl(wpNodeRef, userName);
}
return userRole;
}
private String getWebUserRoleImpl(NodeRef wpNodeRef, String userName)
{
long start = System.currentTimeMillis();
String userRole = null;
StringBuilder query = new StringBuilder(128);
query.append("+PARENT:\"").append(wpNodeRef).append("\" ");
query.append("+TYPE:\"").append(WCMAppModel.TYPE_WEBUSER).append("\" ");
@@ -852,7 +825,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
{
logger.warn("getWebProjectUserRole: more than one user role found for " + userName);
}
}
if (logger.isTraceEnabled())
{
@@ -867,7 +839,7 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
*/
public NodeRef findWebProjectNodeFromPath(String absoluteAVMPath)
{
return findWebProjectNodeFromStore(WCMUtil.getStoreIdFromPath(absoluteAVMPath));
return findWebProjectNodeFromStore(WCMUtil.getWebProjectStoreIdFromPath(absoluteAVMPath));
}
/*(non-Javadoc)
@@ -938,13 +910,18 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
*/
public void inviteWebUsersGroups(String wpStoreId, Map<String, String> userGroupRoles)
{
inviteWebUsersGroups(findWebProjectNodeFromStore(wpStoreId), userGroupRoles);
inviteWebUsersGroups(findWebProjectNodeFromStore(wpStoreId), userGroupRoles, false);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.webproject.WebProjectService#inviteWebUsers(org.alfresco.service.cmr.repository.NodeRef, java.util.Map)
* @see org.alfresco.wcm.webproject.WebProjectService#inviteWebUsersGroups(java.lang.String, java.util.Map, boolean)
*/
public void inviteWebUsersGroups(NodeRef wpNodeRef, Map<String, String> userGroupRoles)
public void inviteWebUsersGroups(String wpStoreId, Map<String, String> userGroupRoles, boolean autoCreateAuthorSandbox)
{
inviteWebUsersGroups(findWebProjectNodeFromStore(wpStoreId), userGroupRoles, autoCreateAuthorSandbox);
}
public void inviteWebUsersGroups(NodeRef wpNodeRef, Map<String, String> userGroupRoles, boolean autoCreateAuthorSandbox)
{
if (! isContentManager(wpNodeRef))
{
@@ -954,13 +931,11 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
WebProjectInfo wpInfo = getWebProject(wpNodeRef);
String wpStoreId = wpInfo.getStoreId();
// create a sandbox for each user appropriately with permissions based on role
// build a list of managers who will have full permissions on ALL staging areas
List<String> managers = new ArrayList<String>(4);
Set<String> existingUsers = new HashSet<String>(8);
// website already exists - we are only adding to the existing sandboxes
// so retrieve the list of managers from the existing users and the selected invitees
// retrieve the list of managers from the existing users
for (Map.Entry<String, String> userRole : userGroupRoles.entrySet())
{
String authority = userRole.getKey();
@@ -990,9 +965,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
existingUsers.add(username);
}
// build the sandboxes now we have the manager list and complete user list
// and create an association to a node to represent each invited user
List<SandboxInfo> sandboxInfoList = new LinkedList<SandboxInfo>();
int invitedCount = 0;
@@ -1005,11 +977,14 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
for (String userAuth : findNestedUserAuthorities(authority))
{
// create the sandbox if the invited user does not already have one
if (existingUsers.contains(userAuth) == false)
{
SandboxInfo info = sandboxFactory.createUserSandbox(wpStoreId, managers, userAuth, role);
sandboxInfoList.add(info);
if (autoCreateAuthorSandbox)
{
// create a sandbox for the user with permissions based on role
SandboxInfo sbInfo = sandboxFactory.createUserSandbox(wpStoreId, managers, userAuth, role);
sandboxInfoList.add(sbInfo);
}
sandboxFactory.addStagingAreaUser(wpStoreId, userAuth, role);
@@ -1029,19 +1004,13 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
}
// Bind the post-commit transaction listener with data required for virtualization server notification
CreateSandboxTransactionListener tl = new CreateSandboxTransactionListener(sandboxInfoList, listWebApps(wpNodeRef));
AlfrescoTransactionSupport.bindListener(tl);
if (managersUpdateRequired == true)
{
// walk existing sandboxes and reapply manager permissions to include any new manager users
for (Map.Entry<String, String> userRole : existingUserRoles.entrySet())
{
String username = userRole.getKey();
if (existingUsers.contains(username))
{
// only need to modify the sandboxes we haven't just created
sandboxFactory.updateSandboxManagers(wpStoreId, managers, username);
}
}
sandboxFactory.updateStagingAreaManagers(wpStoreId, wpNodeRef, managers);
sandboxFactory.updateSandboxManagers(wpStoreId, wpNodeRef, managers);
}
// get permissions and roles for a web project folder type
@@ -1066,10 +1035,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
}
// Bind the post-commit transaction listener with data required for virtualization server notification
InviteWebUsersTransactionListener tl = new InviteWebUsersTransactionListener(sandboxInfoList, listWebApps(wpNodeRef));
AlfrescoTransactionSupport.bindListener(tl);
if (logger.isInfoEnabled())
{
logger.info("Invited "+invitedCount+" web users (store id: "+wpStoreId+")");
@@ -1081,13 +1046,21 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
*/
public void inviteWebUser(String wpStoreId, String userAuth, String role)
{
inviteWebUser(findWebProjectNodeFromStore(wpStoreId), userAuth, role);
inviteWebUser(findWebProjectNodeFromStore(wpStoreId), userAuth, role, false);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.webproject.WebProjectService#inviteWebUser(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.lang.String)
* @see org.alfresco.wcm.webproject.WebProjectService#inviteWebUser(java.lang.String, java.lang.String, java.lang.String, boolean)
*/
public void inviteWebUser(NodeRef wpNodeRef, String userAuth, String role)
public void inviteWebUser(String wpStoreId, String userAuth, String role, boolean autoCreateAuthorSandbox)
{
inviteWebUser(findWebProjectNodeFromStore(wpStoreId), userAuth, role, autoCreateAuthorSandbox);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.webproject.WebProjectService#inviteWebUser(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.lang.String, boolean)
*/
public void inviteWebUser(NodeRef wpNodeRef, String userAuth, String role, boolean autoCreateAuthorSandbox)
{
if (! isContentManager(wpNodeRef))
{
@@ -1095,11 +1068,15 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
WebProjectInfo wpInfo = getWebProject(wpNodeRef);
String wpStoreId = wpInfo.getStoreId();
final String wpStoreId = wpInfo.getStoreId();
boolean existingUser = false;
// create a sandbox for the user with permissions based on role
if (isWebUser(wpNodeRef, userAuth))
{
logger.warn("User '"+userAuth+"' already invited to web project: "+wpNodeRef+" (store id: "+wpStoreId+")");
return;
}
else
{
// build a list of managers who will have full permissions on ALL staging areas
List<String> managers = new ArrayList<String>(4);
@@ -1114,43 +1091,28 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
{
managers.add(username);
}
if (username.equals(userAuth))
{
existingUser = true;
break;
}
}
if (existingUser)
if (autoCreateAuthorSandbox)
{
logger.warn("User '"+userAuth+"' already invited to web project: "+wpNodeRef+" (store id: "+wpStoreId+")");
return;
// create a sandbox for the user with permissions based on role
SandboxInfo sbInfo = sandboxFactory.createUserSandbox(wpStoreId, managers, userAuth, role);
List<SandboxInfo> sandboxInfoList = new LinkedList<SandboxInfo>();
sandboxInfoList.add(sbInfo);
// Bind the post-commit transaction listener with data required for virtualization server notification
CreateSandboxTransactionListener tl = new CreateSandboxTransactionListener(sandboxInfoList, listWebApps(wpNodeRef));
AlfrescoTransactionSupport.bindListener(tl);
}
else
{
// if this new user is a manager, we'll need to update the manager permissions applied
// to each existing user sandbox - to ensure that new user has access to them
if (WCMUtil.ROLE_CONTENT_MANAGER.equals(role))
{
managers.add(userAuth);
// walk existing sandboxes and reapply manager permissions to include new manager user
for (Map.Entry<String, String> userRole : existingUserRoles.entrySet())
{
String username = userRole.getKey();
sandboxFactory.updateSandboxManagers(wpStoreId, managers, username);
sandboxFactory.updateSandboxManagers(wpStoreId, wpNodeRef, managers);
}
sandboxFactory.updateStagingAreaManagers(wpStoreId, wpNodeRef, managers);
}
// build the user sandboxes now we have the manager list
// and create an association to a node to represent invited user
List<SandboxInfo> sandboxInfoList = new LinkedList<SandboxInfo>();
SandboxInfo info = sandboxFactory.createUserSandbox(wpStoreId, managers, userAuth, role);
sandboxInfoList.add(info);
sandboxFactory.addStagingAreaUser(wpStoreId, userAuth, role);
@@ -1173,10 +1135,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
}
// Bind the post-commit transaction listener with data required for virtualization server notification
InviteWebUsersTransactionListener tl = new InviteWebUsersTransactionListener(sandboxInfoList, listWebApps(wpNodeRef));
AlfrescoTransactionSupport.bindListener(tl);
if (logger.isInfoEnabled())
{
logger.info("Invited web user: "+userAuth+" (store id: "+wpStoreId+")");
@@ -1202,13 +1160,21 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
*/
public void uninviteWebUser(String wpStoreId, String userAuth)
{
uninviteWebUser(findWebProjectNodeFromStore(wpStoreId), userAuth);
uninviteWebUser(findWebProjectNodeFromStore(wpStoreId), userAuth, false);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.webproject.WebProjectService#uninviteWebUser(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
* @see org.alfresco.wcm.webproject.WebProjectService#uninviteWebUser(java.lang.String, java.lang.String, boolean)
*/
public void uninviteWebUser(NodeRef wpNodeRef, String userAuth)
public void uninviteWebUser(String wpStoreId, String userAuth, boolean autoDeleteAuthorSandbox)
{
uninviteWebUser(findWebProjectNodeFromStore(wpStoreId), userAuth, autoDeleteAuthorSandbox);
}
/* (non-Javadoc)
* @see org.alfresco.wcm.webproject.WebProjectService#uninviteWebUser(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, boolean)
*/
public void uninviteWebUser(NodeRef wpNodeRef, String userAuth, boolean autoDeleteAuthorSandbox)
{
if (! isContentManager(wpNodeRef))
{
@@ -1222,8 +1188,13 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
String wpStoreId = wpInfo.getStoreId();
String userMainStore = WCMUtil.buildUserMainStoreName(wpStoreId, userAuth);
// remove the store reference from the website folder meta-data
List<ChildAssociationRef> userInfoRefs = listWebUserRefs(wpNodeRef);
if (autoDeleteAuthorSandbox)
{
sandboxFactory.deleteSandbox(userMainStore);
}
// remove the store reference from the website folder meta-data (see also WCMUtil.listWebUsers)
List<ChildAssociationRef> userInfoRefs = nodeService.getChildAssocs(wpNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL);
// retrieve the list of managers from the existing users
List<String> managers = new ArrayList<String>(4);
@@ -1246,49 +1217,10 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
if (userAuth.equals(user))
{
// found the sandbox to remove
String path = WCMUtil.buildSandboxRootPath(userMainStore);
// Notify virtualisation server about removing this sandbox.
//
// Implementation note:
//
// Because the removal of virtual webapps in the
// virtualization server is recursive, it only
// needs to be given the name of the main store.
//
// This notification must occur *prior* to purging content
// within the AVM because the virtualization server must list
// the avm_webapps dir in each store to discover which
// virtual webapps must be unloaded. The virtualization
// server traverses the sandbox's stores in most-to-least
// dependent order, so clients don't have to worry about
// accessing a preview layer whose main layer has been torn
// out from under it.
WCMUtil.removeAllVServerWebapps(virtServerRegistry, path, true);
// TODO: Use the .sandbox-id. property to delete all sandboxes,
// rather than assume a sandbox always had a single preview
// layer attached.
// purge the user main sandbox store from the system
avmService.purgeStore(userMainStore);
// remove any locks this user may have
avmLockingService.removeStoreLocks(userMainStore);
// purge the user preview sandbox store from the system
String userPreviewStore = WCMUtil.buildUserPreviewStoreName(wpStoreId, userAuth);
avmService.purgeStore(userPreviewStore);
// remove any locks this user may have
avmLockingService.removeStoreLocks(userPreviewStore);
// remove the association to this web project user meta-data
nodeService.removeChild(wpNodeRef, ref.getChildRef());
// remove permission for the user (also fixes ETWOONE-338 - also need to ensure that last content manager does not uninvite themselves)
// remove permission for the user (also fixes ETWOONE-338)
permissionService.clearPermission(wpNodeRef, userAuth);
if (logger.isInfoEnabled())
@@ -1375,14 +1307,14 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService
}
/**
* Invite Web Users Transaction listener - invoked after commit
* Create Sandbox Transaction listener - invoked after commit
*/
private class InviteWebUsersTransactionListener extends TransactionListenerAdapter
private class CreateSandboxTransactionListener extends TransactionListenerAdapter
{
private List<SandboxInfo> sandboxInfoList;
private List<String> webAppNames;
public InviteWebUsersTransactionListener(List<SandboxInfo> sandboxInfoList, List<String> webAppNames)
public CreateSandboxTransactionListener(List<SandboxInfo> sandboxInfoList, List<String> webAppNames)
{
this.sandboxInfoList = sandboxInfoList;
this.webAppNames = webAppNames;

View File

@@ -241,6 +241,30 @@ public class WebProjectServiceImplTest extends TestCase
WebProjectInfo wpInfo = wpService.createWebProject(TEST_WEBPROJ_DNS+"-create", TEST_WEBPROJ_NAME+"-create", TEST_TITLE, TEST_DESCRIPTION, TEST_DEFAULT_WEBAPP, TEST_USE_AS_TEMPLATE, null);
checkWebProjectInfo(wpInfo, TEST_WEBPROJ_DNS+"-create", TEST_WEBPROJ_NAME+"-create", TEST_TITLE, TEST_DESCRIPTION, TEST_DEFAULT_WEBAPP, TEST_USE_AS_TEMPLATE);
// Duplicate web project dns/store name
try
{
// Try to create duplicate web project dns/store (-ve test)
wpService.createWebProject(TEST_WEBPROJ_DNS+"-create", TEST_WEBPROJ_NAME+"-x", TEST_TITLE+"x", TEST_DESCRIPTION+"x", TEST_DEFAULT_WEBAPP+"x", TEST_USE_AS_TEMPLATE, null);
fail("Shouldn't allow duplicate web project dns/store name");
}
catch (AlfrescoRuntimeException exception)
{
// Expected
}
// Duplicate web project folder/name
try
{
// Try to create duplicate web project folder/name (-ve test)
wpService.createWebProject(TEST_WEBPROJ_DNS+"x", TEST_WEBPROJ_NAME+"-create", TEST_TITLE+"x", TEST_DESCRIPTION+"x", TEST_DEFAULT_WEBAPP+"x", TEST_USE_AS_TEMPLATE, null);
fail("Shouldn't allow duplicate web project folder/name");
}
catch (DuplicateChildNodeNameException exception)
{
// Expected
}
// Mangled case
String dnsName = TEST_WEBPROJ_DNS+"some.unexpected.chars";
String name = dnsName + " name";
@@ -289,30 +313,6 @@ public class WebProjectServiceImplTest extends TestCase
{
// Expected
}
// Duplicate web project dns/store name
try
{
// Try to create duplicate web project dns/store (-ve test)
wpService.createWebProject(TEST_WEBPROJ_DNS+"-create", TEST_WEBPROJ_NAME+"-x", TEST_TITLE+"x", TEST_DESCRIPTION+"x", TEST_DEFAULT_WEBAPP+"x", TEST_USE_AS_TEMPLATE, null);
fail("Shouldn't allow duplicate web project dns/store name");
}
catch (AlfrescoRuntimeException exception)
{
// Expected
}
// Duplicate web project folder/name
try
{
// Try to create duplicate web project folder/name (-ve test)
wpService.createWebProject(TEST_WEBPROJ_DNS+"x", TEST_WEBPROJ_NAME+"-create", TEST_TITLE+"x", TEST_DESCRIPTION+"x", TEST_DEFAULT_WEBAPP+"x", TEST_USE_AS_TEMPLATE, null);
fail("Shouldn't allow duplicate web project folder/name");
}
catch (DuplicateChildNodeNameException exception)
{
// Expected
}
}
private void checkWebProjectInfo(WebProjectInfo wpInfo, String expectedStoreId, String expectedName, String expectedTitle,
@@ -525,7 +525,7 @@ public class WebProjectServiceImplTest extends TestCase
wpInfo = wpService.createWebProject(TEST_WEBPROJ_DNS+"-delete2", TEST_WEBPROJ_NAME+"-delete2", TEST_TITLE, TEST_DESCRIPTION, TEST_DEFAULT_WEBAPP, true, null);
assertNotNull(wpService.getWebProject(wpInfo.getStoreId()));
wpService.inviteWebUser(wpInfo.getNodeRef(), USER_ONE, WCMUtil.ROLE_CONTENT_MANAGER);
wpService.inviteWebUser(wpInfo.getNodeRef(), USER_ONE, WCMUtil.ROLE_CONTENT_MANAGER, false);
// Switch to USER_TWO
AuthenticationUtil.setCurrentUser(USER_TWO);
@@ -749,7 +749,7 @@ public class WebProjectServiceImplTest extends TestCase
userGroupRoles.put(USER_THREE, WCMUtil.ROLE_CONTENT_REVIEWER);
// Invite web users - test using wpNodeRef
wpService.inviteWebUsersGroups(wpNodeRef, userGroupRoles);
wpService.inviteWebUsersGroups(wpNodeRef, userGroupRoles, false);
assertEquals(4, wpService.listWebUsers(wpNodeRef).size());
assertEquals(WCMUtil.ROLE_CONTENT_MANAGER, wpService.listWebUsers(wpNodeRef).get(USER_ADMIN));
@@ -763,11 +763,15 @@ public class WebProjectServiceImplTest extends TestCase
webProjects = wpService.listWebProjects();
assertEquals(userOneWebProjectCount+1, webProjects.size());
// Start: Test fix ETWOTWO-567
// Test newly invited content manager can invite other
userGroupRoles = new HashMap<String, String>();
userGroupRoles.put(USER_FIVE, WCMUtil.ROLE_CONTENT_CONTRIBUTOR);
wpService.inviteWebUsersGroups(wpNodeRef, userGroupRoles);
wpService.inviteWebUsersGroups(wpNodeRef, userGroupRoles, false);
// Finish: Test fix ETWOTWO-567
// Switch back to admin
AuthenticationUtil.setCurrentUser(USER_ADMIN);
@@ -818,7 +822,7 @@ public class WebProjectServiceImplTest extends TestCase
wpService.inviteWebUser(wpInfo.getStoreId(), USER_ONE, WCMUtil.ROLE_CONTENT_PUBLISHER);
// Invite one web user - test using wpNodeRef
wpService.inviteWebUser(wpNodeRef, USER_TWO, WCMUtil.ROLE_CONTENT_MANAGER);
wpService.inviteWebUser(wpNodeRef, USER_TWO, WCMUtil.ROLE_CONTENT_MANAGER, true);
assertEquals(3, wpService.listWebUsers(wpNodeRef).size());
assertEquals(WCMUtil.ROLE_CONTENT_PUBLISHER, wpService.listWebUsers(wpNodeRef).get(USER_ONE));
@@ -831,8 +835,8 @@ public class WebProjectServiceImplTest extends TestCase
assertEquals(1, wpService.listWebUsers(wpNodeRef2).size());
assertEquals(WCMUtil.ROLE_CONTENT_MANAGER, wpService.listWebUsers(wpNodeRef2).get(USER_ADMIN));
wpService.inviteWebUser(wpNodeRef2, USER_TWO, WCMUtil.ROLE_CONTENT_PUBLISHER);
wpService.inviteWebUser(wpNodeRef2, USER_ONE, WCMUtil.ROLE_CONTENT_MANAGER);
wpService.inviteWebUser(wpNodeRef2, USER_TWO, WCMUtil.ROLE_CONTENT_PUBLISHER, false);
wpService.inviteWebUser(wpNodeRef2, USER_ONE, WCMUtil.ROLE_CONTENT_MANAGER, false);
assertEquals(3, wpService.listWebUsers(wpNodeRef2).size());
assertEquals(WCMUtil.ROLE_CONTENT_PUBLISHER, wpService.listWebUsers(wpNodeRef2).get(USER_TWO));
@@ -850,7 +854,7 @@ public class WebProjectServiceImplTest extends TestCase
try
{
// Try to invite web user as a non-content-manager (-ve test)
wpService.inviteWebUser(wpNodeRef2, USER_THREE, WCMUtil.ROLE_CONTENT_REVIEWER);
wpService.inviteWebUser(wpNodeRef2, USER_THREE, WCMUtil.ROLE_CONTENT_REVIEWER, false);
fail("Shouldn't be able to invite web user since not a content manager");
}
catch (AccessDeniedException exception)
@@ -864,7 +868,7 @@ public class WebProjectServiceImplTest extends TestCase
try
{
// Try to invite web user as a non-content-manager (such as System) (-ve test)
wpService.inviteWebUser(wpNodeRef2, USER_THREE, WCMUtil.ROLE_CONTENT_REVIEWER);
wpService.inviteWebUser(wpNodeRef2, USER_THREE, WCMUtil.ROLE_CONTENT_REVIEWER, false);
fail("Shouldn't be able to invite web user since not a content manager");
}
catch (AccessDeniedException exception)
@@ -878,7 +882,7 @@ public class WebProjectServiceImplTest extends TestCase
AuthenticationUtil.setCurrentUser(USER_ONE);
// Invite web user
wpService.inviteWebUser(wpNodeRef2, USER_THREE, WCMUtil.ROLE_CONTENT_REVIEWER);
wpService.inviteWebUser(wpNodeRef2, USER_THREE, WCMUtil.ROLE_CONTENT_REVIEWER, false);
// Switch back to admin
AuthenticationUtil.setCurrentUser(USER_ADMIN);
@@ -909,12 +913,12 @@ public class WebProjectServiceImplTest extends TestCase
assertEquals(1, wpService.listWebUsers(wpNodeRef).size());
assertEquals(WCMUtil.ROLE_CONTENT_MANAGER, wpService.listWebUsers(wpNodeRef).get(USER_ADMIN));
wpService.inviteWebUser(wpNodeRef, USER_FOUR, WCMUtil.ROLE_CONTENT_CONTRIBUTOR);
wpService.inviteWebUser(wpNodeRef, USER_FOUR, WCMUtil.ROLE_CONTENT_CONTRIBUTOR, false);
assertEquals(2, wpService.listWebUsers(wpNodeRef).size());
assertEquals(WCMUtil.ROLE_CONTENT_CONTRIBUTOR, wpService.listWebUsers(wpNodeRef).get(USER_FOUR));
wpService.inviteWebUser(wpNodeRef, USER_ONE, WCMUtil.ROLE_CONTENT_MANAGER);
wpService.inviteWebUser(wpNodeRef, USER_ONE, WCMUtil.ROLE_CONTENT_MANAGER, false);
assertEquals(3, wpService.listWebUsers(wpNodeRef).size());
assertEquals(WCMUtil.ROLE_CONTENT_MANAGER, wpService.listWebUsers(wpNodeRef).get(USER_ONE));
@@ -931,7 +935,7 @@ public class WebProjectServiceImplTest extends TestCase
try
{
// Try to uninvite web user as a non-content-manager (-ve test)
wpService.uninviteWebUser(wpNodeRef, USER_FOUR);
wpService.uninviteWebUser(wpNodeRef, USER_FOUR, false);
fail("Shouldn't be able to uninvite web user since not a content manager");
}
catch (AccessDeniedException exception)
@@ -945,7 +949,7 @@ public class WebProjectServiceImplTest extends TestCase
try
{
// Try to uninvite web user as a non-content-manager (such as System) (-ve test)
wpService.uninviteWebUser(wpNodeRef, USER_FOUR);
wpService.uninviteWebUser(wpNodeRef, USER_FOUR, false);
fail("Shouldn't be able to uninvite web user since not a content manager");
}
catch (AccessDeniedException exception)
@@ -973,7 +977,7 @@ public class WebProjectServiceImplTest extends TestCase
// Content manager can uninvite themself
// Uninvite web user - test using wpNodeRef
wpService.uninviteWebUser(wpNodeRef, USER_ADMIN);
wpService.uninviteWebUser(wpNodeRef, USER_ADMIN, false);
assertEquals(1, wpService.listWebUsers(wpNodeRef).size());
assertEquals(null, wpService.listWebUsers(wpNodeRef).get(USER_ADMIN));
@@ -985,7 +989,7 @@ public class WebProjectServiceImplTest extends TestCase
assertEquals(WCMUtil.ROLE_CONTENT_MANAGER, wpService.listWebUsers(wpNodeRef).get(USER_ONE));
// Delete user (in this case, last invited content manager)
wpService.uninviteWebUser(wpNodeRef, USER_ONE);
wpService.uninviteWebUser(wpNodeRef, USER_ONE, false);
try
{
@@ -1055,7 +1059,7 @@ public class WebProjectServiceImplTest extends TestCase
{
userRoles.put(TEST_USER+"-"+j, WCMUtil.ROLE_CONTENT_MANAGER);
}
wpService.inviteWebUsersGroups(wpInfo.getNodeRef(), userRoles);
wpService.inviteWebUsersGroups(wpInfo.getNodeRef(), userRoles, false);
}
System.out.println("testPseudoScaleTest: invited "+SCALE_USERS+" content managers to each of "+SCALE_WEBPROJECTS+" web projects in "+(System.currentTimeMillis()-split)+" msecs");
@@ -1064,7 +1068,7 @@ public class WebProjectServiceImplTest extends TestCase
for (int i = 1; i <= SCALE_USERS; i++)
{
wpService.listWebProjects(TEST_USER+"-"+i); // ignore return
assertEquals(SCALE_WEBPROJECTS, wpService.listWebProjects(TEST_USER+"-"+i).size());
}
System.out.println("testPseudoScaleTest: list web projects for "+SCALE_USERS+" content managers in "+(System.currentTimeMillis()-split)+" msecs");

View File

@@ -0,0 +1,73 @@
package org.alfresco.wcm.webproject.script;
import java.util.HashMap;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.jscript.ClasspathScriptLocation;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.ScriptLocation;
import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.util.BaseAlfrescoSpringTest;
import org.alfresco.util.PropertyMap;
public class ScriptWebProjectsTest extends BaseAlfrescoSpringTest {
private static final String USER_ONE = "WebProjectTestOne";
private static final String USER_TWO = "WebProjectTestTwo";
private static final String USER_THREE = "WebProjectTestThree";
private static final String URL_WEB_PROJECTS = "/api/wcm/webprojects";
private AuthenticationService authenticationService;
private PersonService personService;
private ScriptService scriptService;
private AuthenticationComponent authenticationComponent;
private void createUser(String userName)
{
if (this.authenticationService.authenticationExists(userName) == false)
{
this.authenticationService.createAuthentication(userName, "PWD".toCharArray());
PropertyMap ppOne = new PropertyMap(4);
ppOne.put(ContentModel.PROP_USERNAME, userName);
ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");
ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
this.personService.createPerson(ppOne);
}
}
protected void onSetUpInTransaction() throws Exception
{
super.onSetUpInTransaction();
this.scriptService = (ScriptService)this.applicationContext.getBean("ScriptService");
this.authenticationService = (AuthenticationService)this.applicationContext.getBean("AuthenticationService");
this.authenticationComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");
this.personService = (PersonService)this.applicationContext.getBean("PersonService");
// Create users
createUser(USER_ONE);
createUser(USER_TWO);
createUser(USER_THREE);
// Do tests as user one
this.authenticationComponent.setCurrentUser(USER_ONE);
}
public void testJSAPI() throws Exception
{
this.authenticationComponent.setCurrentUser("admin");
ScriptLocation location = new ClasspathScriptLocation("org/alfresco/wcm/webproject/script/test_WebProjectService.js");
this.scriptService.executeScript(location, new HashMap<String, Object>(0));
}
}

View File

@@ -25,18 +25,21 @@
package org.alfresco.wcm.webproject.script;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.repo.jscript.ScriptableHashMap;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.wcm.webproject.WebProjectInfo;
import org.alfresco.wcm.webproject.WebProjectService;
import com.sun.corba.se.spi.orbutil.fsm.Guard.Result;
import org.alfresco.wcm.sandbox.SandboxInfo;
import org.alfresco.wcm.sandbox.SandboxService;
import org.alfresco.wcm.sandbox.script.Sandbox;
/**
* WebProject object to expose via JavaScript
*
*/
public class WebProject implements Serializable
{
@@ -50,8 +53,6 @@ public class WebProject implements Serializable
*/
private static final long serialVersionUID = -2194205151549790079L;
WebProjectService service;
WebProjectInfo info;
private String name;
@@ -59,11 +60,12 @@ public class WebProject implements Serializable
private String description;
private boolean isTemplate;
private String webProjectRef;
private WebProjects webprojects;
/*
* Constructor for Outbound WebProjects
*/
public WebProject(WebProjectInfo info, WebProjectService service)
public WebProject(WebProjects webprojects, WebProjectInfo info)
{
this.info = info;
this.name = info.getName();
@@ -71,7 +73,7 @@ public class WebProject implements Serializable
this.description = info.getDescription();
this.isTemplate = info.isTemplate();
this.webProjectRef = info.getStoreId();
this.service = service;
this.webprojects = webprojects;
}
public void setName(String name) {
@@ -123,16 +125,23 @@ public class WebProject implements Serializable
}
//
public String getWebProjectRef() {
public String getWebProjectRef()
{
return webProjectRef;
}
// read-only property
public NodeRef getNodeRef()
{
return info.getNodeRef();
}
/**
* delete this web project
*/
public void deleteWebProject()
{
service.deleteWebProject(webProjectRef);
getWebProjectService().deleteWebProject(webProjectRef);
}
/**
@@ -140,7 +149,74 @@ public class WebProject implements Serializable
*/
public void save()
{
service.updateWebProject(info);
getWebProjectService().updateWebProject(info);
}
/**
* getSandboxes
* @param userName
* @return the sandboxes or an empty map if there are none.
*/
public ScriptableHashMap<String, Sandbox> getSandboxes(String userName)
{
ScriptableHashMap<String, Sandbox> result = new ScriptableHashMap<String, Sandbox>();
// TODO at the moment the user can only have one sandbox - this will change in future
SandboxInfo si = getSandboxService().getAuthorSandbox(webProjectRef, userName);
if(si != null)
{
Sandbox sandbox = new Sandbox(this, si);
result.put(userName, sandbox);
}
return result;
}
/**
* Create a user sandbox, if the user already has a sandbox does nothing.
* @param userName
* @return the newly created sandbox details
*/
public Sandbox createSandbox(String userName)
{
SandboxInfo si = getSandboxService().createAuthorSandbox(webProjectRef, userName);
Sandbox sandbox = new Sandbox(this, si);
return sandbox;
}
/**
* Get a single sandbox by its unique reference
* @param sandboxRef
* @return the sandbox or null if it is not found.
*/
public Sandbox getSandbox(String sandboxRef)
{
SandboxInfo si = getSandboxService().getSandbox(sandboxRef);
if(si != null)
{
Sandbox sandbox = new Sandbox(this, si);
return sandbox;
}
return null;
}
/**
* getSandboxes for this web project
* @return the sandboxes
*/
public ScriptableHashMap<String, Sandbox> getSandboxes()
{
List<SandboxInfo> si = getSandboxService().listSandboxes(webProjectRef);
ScriptableHashMap<String, Sandbox> result = new ScriptableHashMap<String, Sandbox>();
for(SandboxInfo s : si)
{
Sandbox b = new Sandbox(this, s);
result.put(b.getSandboxRef(), b);
}
return result;
}
/**
@@ -153,7 +229,7 @@ public class WebProject implements Serializable
*/
public String getMembersRole(String userName)
{
return service.getWebUserRole(webProjectRef, userName);
return getWebProjectService().getWebUserRole(webProjectRef, userName);
}
/**
@@ -170,7 +246,7 @@ public class WebProject implements Serializable
*/
public void addMembership(String userName, String role)
{
service.inviteWebUser(webProjectRef, userName, role);
getWebProjectService().inviteWebUser(webProjectRef, userName, role);
}
/**
@@ -183,7 +259,7 @@ public class WebProject implements Serializable
*/
public void removeMembership(String userName)
{
service.uninviteWebUser(webProjectRef, userName);
getWebProjectService().uninviteWebUser(webProjectRef, userName);
}
/**
@@ -193,7 +269,7 @@ public class WebProject implements Serializable
*/
public ScriptableHashMap<String, String> listMembers()
{
Map<String, String> members = service.listWebUsers(webProjectRef);
Map<String, String> members = getWebProjectService().listWebUsers(webProjectRef);
ScriptableHashMap<String, String> result = new ScriptableHashMap<String, String>();
result.putAll(members);
@@ -203,12 +279,36 @@ public class WebProject implements Serializable
/**
* List the role (name) for a WCM project
* @return the roles for a WCM project
* @return a map of roles for a WCM project (value, name)
*/
public ScriptableHashMap<String, String> getRoles()
{
// TODO Not yet implemented.
//TODO Role names should be I811N from webclient.properties
//ContentManager=Content Manager
//ContentPublisher=Content Publisher
//ContentContributor=Content Contributor
//ContentReviewer=Content Reviewer
ScriptableHashMap<String, String> result = new ScriptableHashMap<String, String>();
result.put(ROLE_CONTENT_MANAGER, "Content Manager");
result.put(ROLE_CONTENT_PUBLISHER, "Content Publisher");
result.put(ROLE_CONTENT_REVIEWER, "Content Reviewer");
result.put(ROLE_CONTENT_CONTRIBUTOR, "Content Contributor");
return result;
}
public WebProjects getWebProjects()
{
return this.webprojects;
}
public SandboxService getSandboxService()
{
return getWebProjects().getSandboxService();
}
public WebProjectService getWebProjectService()
{
return getWebProjects().getWebProjectService();
}
}

View File

@@ -30,6 +30,7 @@ import org.alfresco.repo.jscript.BaseScopableProcessorExtension;
import org.alfresco.repo.model.Repository;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.wcm.sandbox.SandboxService;
import org.alfresco.wcm.webproject.WebProjectInfo;
import org.alfresco.wcm.webproject.WebProjectService;
@@ -44,9 +45,12 @@ public class WebProjects extends BaseScopableProcessorExtension
/** Service Registry */
private ServiceRegistry serviceRegistry;
/** The site service */
/** The web projects service */
private WebProjectService webProjectService;
/** The sandbox service */
private SandboxService sandboxService;
/**
* Sets the Service Registry
*
@@ -67,6 +71,26 @@ public class WebProjects extends BaseScopableProcessorExtension
this.webProjectService = webProjectService;
}
public WebProjectService getWebProjectService()
{
return this.webProjectService;
}
/**
* Set the wcm sandbox service
*
* @param webProjectService the wcm web project service
*/
public void setSandboxService(SandboxService sandboxService)
{
this.sandboxService = sandboxService;
}
public SandboxService getSandboxService()
{
return this.sandboxService;
}
/**
* create web project
* @param name
@@ -77,7 +101,7 @@ public class WebProjects extends BaseScopableProcessorExtension
public WebProject createWebProject(String dnsName, String name, String title, String description )
{
WebProjectInfo info = webProjectService.createWebProject(dnsName, name, title, description);
return new WebProject(info, webProjectService);
return new WebProject(this, info);
}
/**
@@ -90,7 +114,7 @@ public class WebProjects extends BaseScopableProcessorExtension
WebProjectInfo info = webProjectService.getWebProject(webProjectRef);
if(info != null){
WebProject retVal = new WebProject(info, webProjectService);
WebProject retVal = new WebProject(this, info);
return retVal;
}
return null;
@@ -109,7 +133,7 @@ public class WebProjects extends BaseScopableProcessorExtension
int i= 0;
for(WebProjectInfo info : projects)
{
ret[i++] = new WebProject(info, webProjectService);
ret[i++] = new WebProject(this, info);
}
return ret;
}
@@ -127,7 +151,7 @@ public class WebProjects extends BaseScopableProcessorExtension
int i= 0;
for(WebProjectInfo info : projects)
{
ret[i++] = new WebProject(info, webProjectService);
ret[i++] = new WebProject(this, info);
}
return ret;
}

View File

@@ -0,0 +1,45 @@
/**
* Test WCM Web Project Java Script Interface
*/
function testListWebProjects()
{
var service = webprojects;
test.assertNotNull(service, "Service is null.");
var list1 = service.listWebProjects();
var length = list1.length;
var newProjA = service.createWebProject("TestA", "test a website", "description", "jsTestA");
var newProjB = service.createWebProject("TestB", "test b website", "description", "jsTestB");
var newProjC = service.createWebProject("TestC", "test c website", "description", "jsTestC");
var list2 = service.listWebProjects();
test.assertNotNull(list2, "list2 is null.");
test.assertTrue(list2.length >= 3 + length, "list too small");
newProjA.deleteWebProject();
newProjB.deleteWebProject();
newProjC.deleteWebProject();
}
function testCRUD()
{
var service = webprojects;
test.assertNotNull(service, "Service is null.");
// Try and get a web project that doesn't exist.
var newProj = service.createWebProject("name", "title", "description", "jsTest");
var node = newProj.getNodeRef();
test.assertNotNull(node.id, "node.id is null.");
newProj.deleteWebProject();
}
// Execute test's
testCRUD();
testListWebProjects();