Merge from HEAD to WCM-DEV2.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3659 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Britt Park
2006-09-02 18:19:00 +00:00
parent db3c29b45e
commit 820da6ecab
147 changed files with 9873 additions and 1289 deletions

View File

@@ -77,6 +77,7 @@ public interface ContentModel
static final QName PROP_SYS_VERSION_SCHEMA = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionSchema");
static final QName PROP_SYS_VERSION_EDITION = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionEdition");
//
// Content Model Definitions
//
@@ -189,6 +190,12 @@ public interface ContentModel
public static final QName ASPECT_MOUNTED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mounted");
public static final QName PROP_MOUNTPOINT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "mountpoint");
// countable aspect
public static final QName ASPECT_COUNTABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "countable");
public static final QName PROP_HITS = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "hits");
public static final QName PROP_COUNTER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "counter");
//
// Application Model Definitions
//

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.action.executer;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
/**
* Simple action to increment an integer value. The runtime NodeService is used so any user
* can increment the counter value on a node.
*
* @author Kevin Roast
*/
public class CounterIncrementActionExecuter extends ActionExecuterAbstractBase
{
/** Runtime NodeService with no permissions protection */
private NodeService nodeService;
/**
* @param nodeService The Runtime NodeService to set.
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef)
*/
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
// add the cm:countable aspect as required
if (this.nodeService.hasAspect(actionedUponNodeRef, ContentModel.ASPECT_COUNTABLE) == false)
{
// set the value to 1 by default
Map<QName, Serializable> props = new HashMap<QName, Serializable>(1);
props.put(ContentModel.PROP_COUNTER, 1);
this.nodeService.addAspect(actionedUponNodeRef, ContentModel.ASPECT_COUNTABLE, props);
}
else
{
// increment the value and handle possibility that no value has been set yet
int resultValue = 1;
Integer value = (Integer)this.nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_COUNTER);
if (value != null)
{
resultValue = value.intValue() + 1;
}
this.nodeService.setProperty(actionedUponNodeRef, ContentModel.PROP_COUNTER, resultValue);
}
}
/**
* @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List)
*/
protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{
// none required
}
}

View File

@@ -32,9 +32,13 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.PersonService;
/**
* Action to execute a JavaScript. The script has access to the default model.
* The actionedUponNodeRef is added to the default model as the 'document' and the owning
* NodeRef is added as the 'space'.
*
* @author Kevin Roast
*/
public class ScriptActionExecutor extends ActionExecuterAbstractBase
public class ScriptActionExecuter extends ActionExecuterAbstractBase
{
public static final String NAME = "script";
public static final String PARAM_SCRIPTREF = "script-ref";

View File

@@ -60,7 +60,7 @@ public class PatchExecuter implements ApplicationListener
{
logger.info(I18NUtil.getMessage(MSG_CHECKING));
Date before = new Date(System.currentTimeMillis() - 20000L); // 20 seconds ago
Date before = new Date(System.currentTimeMillis() - 60000L); // 60 seconds ago
patchService.applyOutstandingPatches();
Date after = new Date(System .currentTimeMillis() + 20000L); // 20 seconds ahead

View File

@@ -20,7 +20,7 @@ import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.service.cmr.admin.PatchException;
/**
* This patch ensures that an upgrade script has been executed. Upgrade scripts
* This patch ensures that an upgrade scriptUrl has been executed. Upgrade scripts
* should create an entry for the patch with the required ID and execution status
* so that the code in this class is never called. If called, an exception message
* is always generated.
@@ -31,26 +31,37 @@ public class SchemaUpgradeScriptPatch extends AbstractPatch
{
private static final String MSG_NOT_EXECUTED = "patch.schemaUpgradeScript.err.not_executed";
private String scriptName;
private String scriptUrl;
public SchemaUpgradeScriptPatch()
{
}
/**
* @return Returns the URL of the scriptUrl that has to have been run
*/
public String getScriptUrl()
{
return scriptUrl;
}
/**
* Set the name of the upgrade script to execute.
* Set the URL of the upgrade scriptUrl to execute. This is the full URL of the
* file, e.g. <b>classpath:alfresco/patch/scripts/upgrade-1.4/${hibernate.dialect.class}/patchAlfrescoSchemaUpdate-1.4-2.sql</b>
* where the <b>${hibernate.dialect.class}</b> placeholder will be substituted with the Hibernate
* <code>Dialect</code> as configured for the system.
*
* @param scriptName the script filename
* @param scriptUrl the scriptUrl filename
*/
public void setScriptName(String scriptName)
public void setScriptUrl(String script)
{
this.scriptName = scriptName;
this.scriptUrl = script;
}
protected void checkProperties()
{
super.checkProperties();
checkPropertyNotNull(scriptName, "scriptName");
checkPropertyNotNull(scriptUrl, "scriptUrl");
}
/**
@@ -59,6 +70,6 @@ public class SchemaUpgradeScriptPatch extends AbstractPatch
@Override
protected String applyInternal() throws Exception
{
throw new PatchException(MSG_NOT_EXECUTED, scriptName);
throw new PatchException(MSG_NOT_EXECUTED, scriptUrl);
}
}

View File

@@ -216,6 +216,9 @@ public class UniqueChildNamePatch extends AbstractPatch
writeLine(" Replaced with: " + usedChildName);
}
}
// clear the session to preserve memory
getSession().flush();
getSession().clear();
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import org.alfresco.service.cmr.repository.NodeRef;
public interface ApplicationAuditModel
{
/**
* Report if audit behaviour can be determined before the method call
*
* @param auditState,
* @param mi
* @return
*/
public AuditMode beforeExecution(AuditMode auditMode, String application, String description,
NodeRef key, Object... args);
/**
* Report if audit behaviour can be determined after the method call
*
* @param auditState,
* @param mi
* @return
*/
public AuditMode afterExecution(AuditMode auditMode, String application, String description,
NodeRef key, Object... args);
/**
* Report if audit behaviour should be invoked on error. It could be we look at the error and filter - this is not supported at the moment.
*
* @param auditState,
* @param mi
* @return
*/
public AuditMode onError(AuditMode auditMode, String application, String description,
NodeRef key, Object... args);
/**
* Get the optional parameters that are to be recorded
*
* @param mi
* @return
*/
public RecordOptions getAuditRecordOptions(String application);
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import org.alfresco.service.cmr.repository.NodeRef;
import org.aopalliance.intercept.MethodInvocation;
/**
* The audit component.
*
* Used by the AuditService and AuditMethodInterceptor to insert audit entries.
*
* @author Andy Hind
*/
public interface AuditComponent
{
/**
* Audit entry point for method interceptors.
*
* @param methodInvocation
*/
public Object audit(MethodInvocation methodInvocation) throws Throwable;
/**
*
* @param source -
* a string that represents the application
* @param description -
* the audit entry *
* @param key -
* a node ref to use as the key for filtering etc
* @param args -
* an arbitrary list of parameters
*/
public void audit(String source, String description, NodeRef key, Object... args);
}

View File

@@ -0,0 +1,425 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.Auditable;
import org.alfresco.service.NotAuditable;
import org.alfresco.service.cmr.repository.NodeRef;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* The default audit component implementation. TODO: Implement before, after and exception filtering. At the moment these filters are ignired. TODO: Respect audit internal - at the
* moment audit internal is fixed to false.
*
* @author Andy Hind
*/
public class AuditComponentImpl implements AuditComponent
{
/**
* The application name to use for audit entries generated by method interception around public services.
*/
private static final String SYSTEM_APPLICATION = "SystemMethodInterceptor";
/**
* Logging
*/
private static Log s_logger = LogFactory.getLog(AuditComponentImpl.class);
/**
* Suspend resume auditing
*/
private static ThreadLocal<Boolean> auditFlag = new ThreadLocal<Boolean>();
/**
* IOC
*/
private PublicServiceIdentifier publicServiceIdentifier;
private AuditConfiguration auditConfiguration;
private AuditDAO auditDAO;
private AuditDAO auditFailedDAO;
private AuditModel auditModel;
/**
* Keep hold of the host where the audit occurs. TODO: Check that we get the correct address ...
*/
private InetAddress auditHost;
public AuditComponentImpl()
{
super();
// Initialise the host address
try
{
auditHost = InetAddress.getLocalHost();
}
catch (UnknownHostException e)
{
s_logger.error("Failed to get local host address", e);
}
}
/*
* IOC property setters
*/
public void setAuditDAO(AuditDAO auditDAO)
{
this.auditDAO = auditDAO;
}
public void setAuditFailedDAO(AuditDAO auditFailedDAO)
{
this.auditFailedDAO = auditFailedDAO;
}
public void setAuditConfiguration(AuditConfiguration auditConfiguration)
{
this.auditConfiguration = auditConfiguration;
}
public void setPublicServiceIdentifier(PublicServiceIdentifier publicServiceIdentifier)
{
this.publicServiceIdentifier = publicServiceIdentifier;
}
public void setAuditModel(AuditModel auditModel)
{
this.auditModel = auditModel;
}
public Object audit(MethodInvocation mi) throws Throwable
{
if ((auditFlag.get() == null) || (!auditFlag.get().booleanValue()))
{
try
{
auditFlag.set(Boolean.TRUE);
Method method = mi.getMethod();
String methodName = method.getName();
String serviceName = publicServiceIdentifier.getPublicServiceName(mi);
if (method.isAnnotationPresent(Auditable.class))
{
if (serviceName != null)
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("Auditing - " + serviceName + "." + methodName);
}
return auditImpl(mi);
}
else
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("UnknownService." + methodName);
}
return auditImpl(mi);
}
}
else if (method.isAnnotationPresent(NotAuditable.class))
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("Not Audited. " + serviceName + "." + methodName);
}
return mi.proceed();
}
else
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("Unannotated service method " + serviceName + "." + methodName);
}
throw new RuntimeException("Unannotated service method " + serviceName + "." + methodName);
}
}
finally
{
auditFlag.set(Boolean.FALSE);
}
}
else
{
return mi.proceed();
}
}
/**
* Audit a method invocation
*/
public Object auditImpl(MethodInvocation mi) throws Throwable
{
AuditInfo auditInfo = new AuditInfo(auditConfiguration);
// RecordOptions recordOptions = auditModel.getAuditRecordOptions(mi);
AuditMode auditMode = AuditMode.UNSET;
try
{
auditMode = beforeInvocation(auditMode, auditInfo, mi);
Object o = mi.proceed();
auditMode = postInvocation(auditMode, auditInfo, mi, o);
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.SUCCESS))
{
auditDAO.audit(auditInfo);
}
return o;
}
catch (Throwable t)
{
auditMode = onError(auditMode, auditInfo, mi, t);
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.FAIL))
{
try
{
auditFailedDAO.audit(auditInfo);
}
catch (Throwable tt)
{
throw new AuditException("Failed to audit exception", new Object[] { tt }, t);
}
}
throw t;
}
}
/**
* Helper method to set auditable properties and to determine if auditing is required when an exception is caught in the audited method.
*
* @param auditMode
* @param auditInfo
* @param t
* @return
*/
private AuditMode onError(AuditMode auditMode, AuditInfo auditInfo, MethodInvocation mi, Throwable t)
{
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.FAIL))
{
auditInfo.setFail(true);
auditInfo.setThrowable(t);
}
return auditMode;
}
/**
* Helper method to set audited information after method invocation and to determine if auditing should take place based on the method return value.
*
* @param auditMode
* @param auditInfo
* @param mi
* @param returnObject
* @return
*/
private AuditMode postInvocation(AuditMode auditMode, AuditInfo auditInfo, MethodInvocation mi, Object returnObject)
{
if (returnObject == null)
{
auditInfo.setReturnObject(null);
}
else if (returnObject instanceof Serializable)
{
auditInfo.setReturnObject((Serializable) returnObject);
}
else
{
auditInfo.setReturnObject(returnObject.toString());
}
return auditMode;
}
/**
* Set auditable information and determine if auditing is required before method invocation. This would normally be based on the method arguments.
*
* @param auditMode
* @param auditInfo
* @param mi
* @return
*/
private AuditMode beforeInvocation(AuditMode auditMode, AuditInfo auditInfo, MethodInvocation mi)
{
AuditMode effectiveAuditMode = auditModel.beforeExecution(auditMode, mi);
if (auditMode != AuditMode.NONE)
{
String methodName = mi.getMethod().getName();
String serviceName = publicServiceIdentifier.getPublicServiceName(mi);
auditInfo.setAuditApplication(SYSTEM_APPLICATION);
auditInfo.setAuditConfiguration(auditConfiguration);
auditInfo.setAuditMethod(methodName);
auditInfo.setAuditService(serviceName);
auditInfo.setClientAddress(null);
auditInfo.setDate(new Date());
auditInfo.setFail(false);
auditInfo.setFiltered(false);
auditInfo.setHostAddress(auditHost);
auditInfo.setKeyGUID(null);
auditInfo.setKeyPropertiesAfter(null);
auditInfo.setKeyPropertiesBefore(null);
auditInfo.setKeyStore(null);
auditInfo.setMessage(null);
if (mi.getArguments() != null)
{
Serializable[] serArgs = new Serializable[mi.getArguments().length];
for (int i = 0; i < mi.getArguments().length; i++)
{
if (mi.getArguments()[i] == null)
{
serArgs[i] = null;
}
else if (mi.getArguments()[i] instanceof Serializable)
{
serArgs[i] = (Serializable) mi.getArguments()[i];
}
else
{
serArgs[i] = mi.getArguments()[i].toString();
}
}
auditInfo.setMethodArguments(serArgs);
}
auditInfo.setPath(null);
auditInfo.setReturnObject(null);
auditInfo.setSessionId(null);
auditInfo.setThrowable(null);
auditInfo.setTxId(AlfrescoTransactionSupport.getTransactionId());
auditInfo.setUserIdentifier(AuthenticationUtil.getCurrentUserName());
}
return effectiveAuditMode;
}
/**
* A simple audit entry Currently we ignore filtering here.
*/
public void audit(String source, String description, NodeRef key, Object... args)
{
AuditInfo auditInfo = new AuditInfo(auditConfiguration);
// RecordOptions recordOptions = auditModel.getAuditRecordOptions(mi);
AuditMode auditMode = AuditMode.UNSET;
try
{
auditMode = onApplicationAudit(auditMode, auditInfo, source, description, key, args);
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.SUCCESS))
{
auditDAO.audit(auditInfo);
}
}
catch (Throwable t)
{
auditMode = onError(auditMode, auditInfo, t, source, description, key, args);
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.FAIL))
{
try
{
auditFailedDAO.audit(auditInfo);
}
catch (Throwable tt)
{
throw new AuditException("Failed to audit exception", new Object[] { tt }, t);
}
}
throw new AuditException("Application audit failed", t);
}
}
private AuditMode onApplicationAudit(AuditMode auditMode, AuditInfo auditInfo, String source, String description,
NodeRef key, Object... args)
{
AuditMode effectiveAuditMode = auditModel.beforeExecution(auditMode, source, description, key, args);
if (auditMode != AuditMode.NONE)
{
if(source.equals(SYSTEM_APPLICATION))
{
throw new AuditException("Application audit can not use the reserved identifier "+SYSTEM_APPLICATION);
}
auditInfo.setAuditApplication(source);
auditInfo.setAuditConfiguration(auditConfiguration);
auditInfo.setAuditMethod(null);
auditInfo.setAuditService(null);
auditInfo.setClientAddress(null);
auditInfo.setDate(new Date());
auditInfo.setFail(false);
auditInfo.setFiltered(false);
auditInfo.setHostAddress(auditHost);
auditInfo.setKeyGUID(null);
auditInfo.setKeyPropertiesAfter(null);
auditInfo.setKeyPropertiesBefore(null);
auditInfo.setKeyStore(null);
auditInfo.setMessage(description);
if (args != null)
{
Serializable[] serArgs = new Serializable[args.length];
for (int i = 0; i < args.length; i++)
{
if (args[i] == null)
{
serArgs[i] = null;
}
else if (args[i] instanceof Serializable)
{
serArgs[i] = (Serializable) args[i];
}
else
{
serArgs[i] = args[i].toString();
}
}
auditInfo.setMethodArguments(serArgs);
}
auditInfo.setPath(null);
auditInfo.setReturnObject(null);
auditInfo.setSessionId(null);
auditInfo.setThrowable(null);
auditInfo.setTxId(AlfrescoTransactionSupport.getTransactionId());
auditInfo.setUserIdentifier(AuthenticationUtil.getCurrentUserName());
}
return effectiveAuditMode;
}
private AuditMode onError(AuditMode auditMode, AuditInfo auditInfo, Throwable t, String source, String description,
NodeRef key, Object... args)
{
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.FAIL))
{
auditInfo.setFail(true);
auditInfo.setThrowable(t);
}
return auditMode;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import java.io.InputStream;
/**
* An audit configuration is xml content from an input stream.
*
* @author Andy Hind
*/
public interface AuditConfiguration
{
/**
* Get the XML content for the configuration as a stream.
*
* @return
*/
public abstract InputStream getInputStream();
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import java.io.InputStream;
import org.springframework.beans.factory.InitializingBean;
/**
* A class to read the audit configuration from the class path
*
* @author Andy Hind
*/
public class AuditConfigurationImpl implements InitializingBean, AuditConfiguration
{
private String config;
public AuditConfigurationImpl()
{
super();
}
public void setConfig(String config)
{
this.config = config;
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.getInputStream#getInputStream()
*/
/* (non-Javadoc)
* @see org.alfresco.repo.audit.AuditConfiguration#getInputStream()
*/
public InputStream getInputStream()
{
InputStream is = this.getClass().getClassLoader().getResourceAsStream(config);
return is;
}
public void afterPropertiesSet() throws Exception
{
// Read and set up the audit configuration
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
/**
* The interface to persist audit information.
*
* @author Andy Hind
*/
public interface AuditDAO
{
/**
* Create an audit entry.
*
* @param auditInfo
*/
public void audit(AuditInfo auditInfo);
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import org.alfresco.error.AlfrescoRuntimeException;
/**
* Audit related exceptions.
*
* @author Andy Hind
*/
public class AuditException extends AlfrescoRuntimeException
{
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = -7947190775692164588L;
public AuditException(String msgId)
{
super(msgId);
}
public AuditException(String msgId, Object[] msgParams)
{
super(msgId, msgParams);
}
public AuditException(String msgId, Throwable cause)
{
super(msgId, cause);
}
public AuditException(String msgId, Object[] msgParams, Throwable cause)
{
super(msgId, msgParams, cause);
}
}

View File

@@ -0,0 +1,385 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Map;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.apache.log4j.Logger;
/**
* A class to encapsulate audit information supplied to the DAO layer.
*
* Null entries should be stored.
*
* @author Andy Hind
*/
public class AuditInfo
{
private static Logger s_logger = Logger.getLogger(AuditInfo.class);
/**
* The user identifier for the person who caused this audit entry
*/
private String userIdentifier;
/**
* The date for this audit entry
*/
private Date date;
/**
* The transaction id in which this entry was made
*/
private String txId;
/**
* The session is for this action
*/
private String sessionId;
/**
* The store in which the action occured.
*/
private StoreRef keyStore;
/**
* For a node ref, the node for the action.
*/
private String keyGUID;
/**
* The path of the key
*/
private String keyPath;
/**
* The audit application
* Internal uses the "System" key and will only audit method information.
*/
private String auditApplication;
/**
* The service holding the audited method.
*/
private String auditService;
/**
* The name of the audited method.
*/
private String auditMethod;
/**
* Did this entry passa filter?
* If false - all entries were being recorded.
*/
private boolean filtered;
/**
* The audit configuration in use at the time.
*/
private AuditConfiguration auditConfiguration;
/**
* The object returned by the audited method.
*/
private Serializable returnObject;
/**
* The arguments to the audited method.
*/
private Serializable[] methodArguments;
/**
* Any Exception thrown by the audited method.
*/
private Throwable throwable;
/**
* Did the audited method throw an exception?
*/
private boolean fail;
/**
* The host address for where the audit was generated.
*/
private InetAddress hostAddress;
private static InetAddress s_hostAddress;
/**
* The client address causing the audit
*/
private InetAddress clientAddress;
/**
* The properties of the key node before the method execution.
*/
private Map<QName, Serializable> keyPropertiesBefore;
/**
* The properties of the key node after the method execution.
*/
private Map<QName, Serializable> keyPropertiesAfter;
/**
* For general auditing - the audit message.
*/
private String message;
static
{
try
{
s_hostAddress = InetAddress.getLocalHost();
}
catch (UnknownHostException e)
{
s_logger.error(e);
s_hostAddress = null;
}
}
public AuditInfo(AuditConfiguration auditConfiguration)
{
super();
// Add default information
userIdentifier = AuthenticationUtil.getCurrentUserName();
date = new Date();
txId = AlfrescoTransactionSupport.getTransactionId();
sessionId = "Unavailable";
hostAddress = s_hostAddress;
}
public String getAuditApplication()
{
return auditApplication;
}
public void setAuditApplication(String auditApplication)
{
this.auditApplication = auditApplication;
}
public AuditConfiguration getAuditConfiguration()
{
return auditConfiguration;
}
public void setAuditConfiguration(AuditConfiguration auditConfiguration)
{
this.auditConfiguration = auditConfiguration;
}
public String getAuditMethod()
{
return auditMethod;
}
public void setAuditMethod(String auditMethod)
{
this.auditMethod = auditMethod;
}
public String getAuditService()
{
return auditService;
}
public void setAuditService(String auditService)
{
this.auditService = auditService;
}
public InetAddress getClientAddress()
{
return clientAddress;
}
public void setClientAddress(InetAddress clientAddress)
{
this.clientAddress = clientAddress;
}
public Date getDate()
{
return date;
}
public void setDate(Date date)
{
this.date = date;
}
public boolean isFail()
{
return fail;
}
public void setFail(boolean fail)
{
this.fail = fail;
}
public boolean isFiltered()
{
return filtered;
}
public void setFiltered(boolean filtered)
{
this.filtered = filtered;
}
public InetAddress getHostAddress()
{
return hostAddress;
}
public void setHostAddress(InetAddress hostAddress)
{
this.hostAddress = hostAddress;
}
public String getKeyGUID()
{
return keyGUID;
}
public void setKeyGUID(String keyGUID)
{
this.keyGUID = keyGUID;
}
public Map<QName, Serializable> getKeyPropertiesAfter()
{
return keyPropertiesAfter;
}
public void setKeyPropertiesAfter(Map<QName, Serializable> keyPropertiesAfter)
{
this.keyPropertiesAfter = keyPropertiesAfter;
}
public Map<QName, Serializable> getKeyPropertiesBefore()
{
return keyPropertiesBefore;
}
public void setKeyPropertiesBefore(Map<QName, Serializable> keyPropertiesBefore)
{
this.keyPropertiesBefore = keyPropertiesBefore;
}
public StoreRef getKeyStore()
{
return keyStore;
}
public void setKeyStore(StoreRef keyStore)
{
this.keyStore = keyStore;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
public Serializable[] getMethodArguments()
{
return methodArguments;
}
public void setMethodArguments(Serializable[] methodArguments)
{
this.methodArguments = methodArguments;
}
public String getPath()
{
return keyPath;
}
public void setPath(String keyPath)
{
this.keyPath = keyPath;
}
public Serializable getReturnObject()
{
return returnObject;
}
public void setReturnObject(Serializable returnObject)
{
this.returnObject = returnObject;
}
public String getSessionId()
{
return sessionId;
}
public void setSessionId(String sessionId)
{
this.sessionId = sessionId;
}
public Throwable getThrowable()
{
return throwable;
}
public void setThrowable(Throwable throwable)
{
this.throwable = throwable;
}
public String getTxId()
{
return txId;
}
public void setTxId(String txId)
{
this.txId = txId;
}
public String getUserIdentifier()
{
return userIdentifier;
}
public void setUserIdentifier(String userIdentifier)
{
this.userIdentifier = userIdentifier;
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* A method interceptor to wrap method invocations with auditing.
*
* A single instance is used to wrap all services. If the single instance is disabled
* no auditing will be carried out and there will be minimal overhead.
*
* @author Andy Hind
*/
public class AuditMethodInterceptor implements MethodInterceptor
{
//private static Log s_logger = LogFactory.getLog(AuditMethodInterceptor.class);
private AuditComponent auditComponent;
private boolean disabled = false;
public AuditMethodInterceptor()
{
super();
}
public void setDisabled(boolean disabled)
{
this.disabled = disabled;
}
public void setAuditComponent(AuditComponent auditComponent)
{
this.auditComponent = auditComponent;
}
public Object invoke(MethodInvocation mi) throws Throwable
{
if(disabled)
{
return mi.proceed();
}
else
{
return auditComponent.audit(mi);
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import org.alfresco.repo.audit.model.AuditModelException;
/**
* An enum to specify the audit mode:
*
* <ol>
* <li> ALL - all calls are audited
* <li> SUCCESS - only successful calls are audited (audited in the same TX)
* <li> FAIL - only fail calls are audited (in a new transaction)
* <li> NONE - noting is audited
* <li> UNSET
* </ol>
*
* The mode is inherited from containers if nothing is specified
*
* @author Andy Hind
*/
public enum AuditMode
{
ALL, SUCCESS, FAIL, NONE, UNSET;
public static AuditMode getAuditMode(String value)
{
if(value.equalsIgnoreCase("all"))
{
return AuditMode.ALL;
}
else if(value.equalsIgnoreCase("success"))
{
return AuditMode.SUCCESS;
}
else if(value.equalsIgnoreCase("fail"))
{
return AuditMode.FAIL;
}
else if(value.equalsIgnoreCase("none"))
{
return AuditMode.NONE;
}
else if(value.equalsIgnoreCase("unset"))
{
return AuditMode.UNSET;
}
else
{
throw new AuditModelException("Invalid audit mode: "+value);
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
/**
* API for querying the audit model
*
* @author Andy Hind
*/
public interface AuditModel extends ApplicationAuditModel, MethodAuditModel
{
/**
* Constants for reading the xml model definition.
*/
/* package */final static String NAME_SPACE = "http://www.alfresco.org/model/audit/1.0";
/* package */final static String EL_AUDIT = "Audit";
/* package */final static String EL_RECORD_OPTIONS = "RecordOptions";
/* package */final static String EL_RECORD_PATH = "recordPath";
/* package */final static String EL_RECORD_FILTERS = "recordFilters";
/* package */final static String EL_RECORD_SER_RETURN_VAL = "recordSerializedReturnValue";
/* package */final static String EL_RECORD_SER_EX = "recordSerializedExceptions";
/* package */final static String EL_RECORD_SER_ARGS = "recordSerializedMethodArguments";
/* package */final static String EL_RECORD_SER_PROP_BEFORE = "recordSerializedKeyPropertiesBeforeInvocation";
/* package */final static String EL_RECORD_SER_PROP_AFTER = "recordSerializedKeyPropertiesAferInvocation";
/* package */final static String EL_FILTER = "Filter";
/* package */final static String EL_METHOD = "Method";
/* package */final static String EL_SERVICE = "Service";
/* package */final static String EL_APPLICATION = "Application";
/* package */final static String EL_EXPRESSION = "Expression";
/* package */final static String EL_PARAMETER_NAME = "ParameterName";
/* package */final static String AT_MODE = "mode";
/* package */final static String AT_ENABLED = "enabled";
/* package */final static String AT_AUDIT_INTERNAL = "auditInternal";
/* package */final static String AT_NAME = "name";
/* package */final static String AT_INVERT = "invert";
/* package */final static String AT_TYPE = "type";
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import javax.transaction.UserTransaction;
import org.alfresco.service.cmr.audit.AuditService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.springframework.context.ApplicationContext;
/**
* The implementation of the AuditService for application auditing.
*
* @author Andy Hind
*/
public class AuditServiceImpl implements AuditService
{
private AuditComponent auditComponent;
public AuditServiceImpl()
{
super();
}
public void setAuditComponent(AuditComponent auditComponent)
{
this.auditComponent = auditComponent;
}
public void audit(String source, String description)
{
auditComponent.audit(source, description, null, (Object[]) null);
}
public void audit(String source, String description, NodeRef key)
{
auditComponent.audit(source, description, key, (Object[]) null);
}
public void audit(String source, String description, Object... args)
{
auditComponent.audit(source, description, null, args);
}
public void audit(String source, String description, NodeRef key, Object... args)
{
auditComponent.audit(source, description, key, args);
}
public static void main(String[] args) throws Exception
{
ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
AuditService as = (AuditService) ctx.getBean("AuditService");
TransactionService txs = (TransactionService) ctx.getBean("transactionComponent");
UserTransaction tx = txs.getUserTransaction();
tx.begin();
as.audit("AuditedApp", "First");
as.audit("AuditedApp", "Second", new NodeRef(new StoreRef("test", "audit"), "id"));
as.audit("AuditedApp", "Third", new Object[]{"one", "two", "three"});
as.audit("AuditedApp", "Fourth", new NodeRef(new StoreRef("test", "audit"), "id"), new Object[]{"one", "two", "three"});
as.audit("UnAuditedApp", "First");
as.audit("UnAuditedApp", "Second", new NodeRef(new StoreRef("test", "audit"), "id"));
as.audit("UnAuditedApp", "Third", new Object[]{"one", "two", "three"});
as.audit("UnAuditedApp", "Fourth", new NodeRef(new StoreRef("test", "audit"), "id"), new Object[]{"one", "two", "three"});
tx.commit();
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import org.aopalliance.intercept.MethodInvocation;
public interface MethodAuditModel
{
/**
* Report if audit behaviour can be determined before the method call
*
* @param auditState,
* @param mi
* @return
*/
public AuditMode beforeExecution(AuditMode auditMode, MethodInvocation mi);
/**
* Report if audit behaviour can be determined after the method call
*
* @param auditState,
* @param mi
* @return
*/
public AuditMode afterExecution(AuditMode auditMode, MethodInvocation mi);
/**
* Report if audit behaviour should be invoked on error. It could be we look at the error and filter - this is not supported at the moment.
*
* @param auditState,
* @param mi
* @return
*/
public AuditMode onError(AuditMode auditMode, MethodInvocation mi);
/**
* Get the optional parameters that are to be recorded
*
* @param mi
* @return
*/
public RecordOptions getAuditRecordOptions(MethodInvocation mi);
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import org.aopalliance.intercept.MethodInvocation;
/**
* This defines the API to identify the public service upon which a method invocation has been made.
*
* @author Andy Hind
*/
public interface PublicServiceIdentifier
{
/**
* Get the name of the public service for the method invocation.
*
* @param mi
* @return
*/
public String getPublicServiceName(MethodInvocation mi);
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.alfresco.service.PublicService;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* Identify public services by method invocation. Look ups are cached on a thread local as they are quite expensive. All public service names end with "Service" and start with
* capital letter. This pattern is used to filter bean names. TODO: Look at pulling out all the mappings at start up.
*
* @author Andy Hind
*/
public class PublicServiceIdentifierImpl implements PublicServiceIdentifier, BeanFactoryPostProcessor
{
private static Log s_logger = LogFactory.getLog(PublicServiceIdentifierImpl.class);
private static ThreadLocal<HashMap<Method, String>> methodToServiceMap = new ThreadLocal<HashMap<Method, String>>();
private ConfigurableListableBeanFactory beanFactory;
public PublicServiceIdentifierImpl()
{
super();
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
{
this.beanFactory = beanFactory;
}
public String getPublicServiceName(MethodInvocation mi)
{
return getServiceName(mi);
}
/**
* Cache service name look up.
*
* @param mi
* @return
* @throws BeansException
*/
private String getServiceName(MethodInvocation mi) throws BeansException
{
if (methodToServiceMap.get() == null)
{
methodToServiceMap.set(new HashMap<Method, String>());
}
Method method = mi.getMethod();
String serviceName = methodToServiceMap.get().get(method);
if (serviceName == null)
{
serviceName = getServiceNameImpl(mi);
methodToServiceMap.get().put(method, serviceName);
}
else
{
if (s_logger.isDebugEnabled())
{
s_logger.debug("Cached look up for " + serviceName + "." + method.getName());
}
}
return serviceName;
}
/**
* Do the look up by interface type.
*
* @param mi
* @return
* @throws BeansException
*/
private String getServiceNameImpl(MethodInvocation mi) throws BeansException
{
Class clazz = mi.getThis().getClass();
while (clazz != null)
{
Class[] interfaces = clazz.getInterfaces();
for (Class iFace : interfaces)
{
Class publicServiceInterface = findPublicService(iFace);
if (publicServiceInterface != null)
{
Map beans = beanFactory.getBeansOfType(publicServiceInterface);
Iterator iter = beans.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry entry = (Map.Entry) iter.next();
String serviceName = (String) entry.getKey();
if ((serviceName.endsWith("Service"))
&& (Character.isUpperCase(serviceName.charAt(0)))
&& !serviceName.equals("DescriptorService"))
{
return serviceName;
}
}
}
}
clazz = clazz.getSuperclass();
}
return null;
}
/**
* We use a marker annotation to identify public interfaces.
* The interfaces have to be walked to determine if a public interface is implemented.
*
* Only one public service interface is expected.
*
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
private Class findPublicService(Class clazz)
{
if (!clazz.isInterface())
{
return null;
}
if (clazz.isAnnotationPresent(PublicService.class))
{
return clazz;
}
Class[] classes = clazz.getInterfaces();
for(Class implemented: classes)
{
Class answer = findPublicService(implemented);
if(answer != null)
{
return answer;
}
}
return null;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit;
import org.alfresco.repo.audit.model.TrueFalseUnset;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.dom4j.Element;
public interface RecordOptions
{
public TrueFalseUnset getRecordFilters();
public TrueFalseUnset getRecordPath();
public TrueFalseUnset getRecordSerializedExceptions();
public TrueFalseUnset getRecordSerializedKeyPropertiesAfterEvaluation();
public TrueFalseUnset getRecordSerializedKeyPropertiesBeforeEvaluation();
public TrueFalseUnset getRecordSerializedMethodArguments();
public TrueFalseUnset getRecordSerializedReturnValue();
}

View File

@@ -0,0 +1,158 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
'-//Hibernate/Hibernate Mapping DTD 3.0//EN'
'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
<!-- Hibernate mapping for storing audit information -->
<!-- -->
<!-- This generates a simple star schema for audit -->
<!-- breakdown and roll up. -->
<!-- -->
<hibernate-mapping>
<!-- The fact -->
<class name="org.alfresco.repo.audit.hibernate.AuditFactImpl" proxy="org.alfresco.repo.audit.hibernate.AuditFact" table="alf_audit_fact" dynamic-update="false" dynamic-insert="false"
select-before-update="false" lazy="true" optimistic-lock="version">
<!-- An auto-generated id -->
<id name="id" column="id" type="long">
<generator class="native"/>
</id>
<!-- Fact properties -->
<property name="userId" column="user_id" type="string" length="255" not-null="true" index="adt_user_idx"/>
<property name="date" column="timestamp" type="timestamp" not-null="true"/>
<property name="transactionId" column="transaction_id" type="string" length="56" not-null="true"/>
<property name="sessionId" column="session_id" type="string" length="56" not-null="false"/>
<property name="storeProtocol" column="store_protocol" type="string" length="50" not-null="false" index="adt_store_idx"/>
<property name="storeId" column="store_id" type="string" length="100" not-null="false" index="adt_store_idx"/>
<property name="nodeUUID" column="node_uuid" type="string" length="36" not-null="false" index="adt_store_idx"/>
<property name="path" column="path" type="string" length="512" not-null="false"/>
<property name="filtered" column="filtered" type="boolean" not-null="true"/>
<property name="returnValue" column="return_val" type="string" length="1024" not-null="false"/>
<property name="arg1" column="arg_1" type="string" length="1024" not-null="false"/>
<property name="arg2" column="arg_2" type="string" length="1024" not-null="false"/>
<property name="arg3" column="arg_3" type="string" length="1024" not-null="false"/>
<property name="arg4" column="arg_4" type="string" length="1024" not-null="false"/>
<property name="arg5" column="arg_5" type="string" length="1024" not-null="false"/>
<property name="fail" column="fail" type="boolean" not-null="true"/>
<!-- TODO: Check the URL length ...-->
<property name="serialisedURL" column="serialized_url" type="string" length="1024" not-null="false"/>
<property name="exception" column="exception" type="string" length="1024" not-null="false"/>
<property name="hostInetAddress" column="host_address" type="string" length="1024" not-null="false"/>
<property name="clientInetAddress" column="client_address" type="string" length="1024" not-null="false"/>
<property name="message" column="message" type="string" length="1024" not-null="false"/>
<!-- Links to dimensions -->
<many-to-one name="auditDate" class="org.alfresco.repo.audit.hibernate.AuditDateImpl" not-null="true" lazy="proxy" column="audit_date_id" cascade="none" optimistic-lock="true" fetch="join"/>
<many-to-one name="auditConfig" class="org.alfresco.repo.audit.hibernate.AuditConfigImpl" not-null="true" lazy="proxy" column="audit_conf_id" cascade="none" optimistic-lock="true" fetch="join"/>
<many-to-one name="auditSource" class="org.alfresco.repo.audit.hibernate.AuditSourceImpl" not-null="true" lazy="proxy" column="audit_source_id" cascade="none" optimistic-lock="true" fetch="join"/>
</class>
<!-- The audit date dimension -->
<class name="org.alfresco.repo.audit.hibernate.AuditDateImpl" proxy="org.alfresco.repo.audit.hibernate.AuditDate" table="alf_audit_date" dynamic-update="false" dynamic-insert="false"
select-before-update="false" lazy="true" optimistic-lock="version">
<!-- An auto-generated id -->
<id name="id" column="id" type="long">
<generator class="native"/>
</id>
<!-- Date is used as the key for look up -->
<property name="date" column="date" type="date" index="adt_date_idx" not-null="true"/>
<property name="dayOfYear" column="day_of_year" type="integer" index="adt_doy_idx" not-null="true"/>
<property name="dayOfMonth" column="day_of_month" type="integer" index="adt_dom_idx" not-null="true"/>
<property name="dayOfWeek" column="day_of_week" type="integer" index="adt_dow_idx" not-null="true"/>
<property name="weekOfYear" column="week_of_year" type="integer" index="adt_woy_idx" not-null="true"/>
<property name="weekOfMonth" column="week_of_month" type="integer" index="adt_wom_idx" not-null="true"/>
<property name="month" column="month" type="integer" index="adt_m_idx" not-null="true"/>
<property name="quarter" column="quarter" type="integer" index="adt_q_idx" not-null="true"/>
<property name="halfYear" column="halfYear" type="integer" index="adt_hy_idx" not-null="true"/>
<property name="year" column="year" type="integer" index="adt_y_idx" not-null="true"/>
</class>
<!-- The audit configuration dimension -->
<class name="org.alfresco.repo.audit.hibernate.AuditConfigImpl" proxy="org.alfresco.repo.audit.hibernate.AuditConfig" table="alf_audit_config" dynamic-update="false" dynamic-insert="false"
select-before-update="false" lazy="true" optimistic-lock="version">
<!-- Max id is used to find the latest audit configuration -->
<!-- An auto-generated id -->
<id name="id" column="id" type="long">
<generator class="native"/>
</id>
<property name="configURL" column="config_url" type="string" length="256" not-null="true"/>
</class>
<!-- The audit source dimension -->
<class name="org.alfresco.repo.audit.hibernate.AuditSourceImpl" proxy="org.alfresco.repo.audit.hibernate.AuditSource" table="alf_audit_source" dynamic-update="false" dynamic-insert="false"
select-before-update="false" lazy="true" optimistic-lock="version">
<!-- An auto-generated id -->
<id name="id" column="id" type="long">
<generator class="native"/>
</id>
<!-- The app_source_idx index is used to find the app source -->
<!-- The look up is always the tripple, the service and method or just the method may be null -->
<property name="application" column="application" type="string" length="256" not-null="true" index="app_source_idx"/>
<property name="service" column="service" type="string" length="256" not-null="false" index="app_source_idx"/>
<property name="method" column="method" type="string" length="256" not-null="false" index="app_source_idx"/>
</class>
<query name="audit.GetLatestAuditDate">
select
audit_date
from
org.alfresco.repo.audit.hibernate.AuditDateImpl as audit_date
where
audit_date.id = (select max(audit_date_2.id) from org.alfresco.repo.audit.hibernate.AuditDateImpl as audit_date_2)
</query>
<query name="audit.GetLatestAuditConfig">
select
audit_config
from
org.alfresco.repo.audit.hibernate.AuditConfigImpl as audit_config
where
audit_config.id = (select max(audit_config_2.id) from org.alfresco.repo.audit.hibernate.AuditConfigImpl as audit_config_2)
</query>
<query name="audit.GetAuditSourceByApplication">
select
audit_store
from
org.alfresco.repo.audit.hibernate.AuditSourceImpl as audit_store
where
audit_store.application = :application and
audit_store.service is null and
audit_store.method is null
</query>
<query name="audit.GetAuditSourceByApplicationServiceMethod">
select
audit_store
from
org.alfresco.repo.audit.hibernate.AuditSourceImpl as audit_store
where
audit_store.application = :application and
audit_store.service = :service and
audit_store.method = :method
</query>
</hibernate-mapping>

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.hibernate;
/**
* Hibernate interface for audit configuration persistence.
*
* @author Andy Hind
*/
public interface AuditConfig
{
/**
* Get the content URL for a copy of the configuration file.
*
* @return
*/
public abstract String getConfigURL();
/**
* Get the surrogate key for the configuration entry.
* The creation is managed by hibernate.
*
* @return
*/
public abstract long getId();
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.hibernate;
import org.alfresco.util.EqualsHelper;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.beans.factory.InitializingBean;
public class AuditConfigImpl implements AuditConfig, InitializingBean
{
/**
* The hibernate generated internal key.
*/
private long id;
/**
* The URL to the content that contains the configuration file
*/
private String configURL;
public AuditConfigImpl()
{
super();
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditContig#getConfigURL()
*/
public String getConfigURL()
{
return configURL;
}
public void setConfigURL(String configURL)
{
this.configURL = configURL;
}
public void afterPropertiesSet() throws Exception
{
// Read the audit configuration
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditContig#getId()
*/
public long getId()
{
return id;
}
/**
* Internal setter for hibernate.
*
* @param id
*/
@SuppressWarnings("unused")
private void setId(long id)
{
this.id = id;
}
/**
* Helper method to get the latest audit config
*/
public static AuditConfigImpl getLatestConfig(Session session)
{
Query query = session.getNamedQuery(HibernateAuditDAO.QUERY_LAST_AUDIT_CONFIG);
return (AuditConfigImpl) query.uniqueResult();
}
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if(!(o instanceof AuditConfigImpl))
{
return false;
}
AuditConfigImpl other = (AuditConfigImpl)o;
return EqualsHelper.nullSafeEquals(this.configURL, other.configURL);
}
@Override
public int hashCode()
{
return configURL == null ? 0 : configURL.hashCode();
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.hibernate;
import java.util.Date;
/**
* Hibernate date dimension for audit roll ups
*
* @author Andy Hind
*/
public interface AuditDate
{
/**
* Get the date
*
* @return
*/
public abstract Date getDate();
/**
* Get the day of the year.
*
* @return
*/
public abstract int getDayOfYear();
/**
* Get the day of the month.
*
* @return
*/
public abstract int getDayOfMonth();
/**
* Get the day of the week
*
* @return
*/
public abstract int getDayOfWeek();
/**
* Get the half year;
*
* @return
*/
public abstract int getHalfYear();
/**
* Get the surrogate key
*
* @return
*/
public abstract long getId();
/**
* Get the month
*
* @return
*/
public abstract int getMonth();
/**
* Get the quarter
*
* @return
*/
public abstract int getQuarter();
/**
* Get the week of the month.
*
* @return
*/
public abstract int getWeekOfMonth();
/**
* Get the week of the year.
*
* @return
*/
public abstract int getWeekOfYear();
/**
* Get the year.
* @return
*/
public abstract int getYear();
}

View File

@@ -0,0 +1,289 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.hibernate;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.alfresco.util.EqualsHelper;
import org.hibernate.Query;
import org.hibernate.Session;
/**
* Hibernate persistence for a date dimension.
*
* @author Andy Hind
*/
public class AuditDateImpl implements AuditDate
{
/**
* Surrogate key
*/
private long id;
/**
* The date
*/
private Date date;
/**
* The day
*/
private int dayOfYear;
/**
* Day of month.
*/
private int dayOfMonth;
/**
* The day of the week
*/
private int dayOfWeek;
/**
* The week in the year
*/
private int weekOfYear;
/**
* The week of the month
*/
private int weekOfMonth;
/**
* The month in the year
*/
private int month;
/**
* The quarter in the year
*/
private int quarter;
/**
* The half year in the year
*/
private int halfYear;
/**
* The year
*/
private int year;
protected AuditDateImpl()
{
super();
}
public AuditDateImpl(Date date)
{
super();
setDate(date);
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getDate()
*/
public Date getDate()
{
return date;
}
public void setDate(Date date)
{
Calendar cal = GregorianCalendar.getInstance();
cal.setTime(date);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.HOUR_OF_DAY, 0);
this.date = cal.getTime();
this.setDayOfYear(cal.get(Calendar.DAY_OF_YEAR));
this.setDayOfMonth(cal.get(Calendar.DAY_OF_MONTH));
this.setDayOfWeek(cal.get(Calendar.DAY_OF_WEEK));
this.setMonth(cal.get(Calendar.MONTH));
this.setHalfYear(getMonth() <= Calendar.JUNE ? 0 : 1);
this.setQuarter((getMonth()/3));
this.setWeekOfMonth(cal.get(Calendar.WEEK_OF_MONTH));
this.setWeekOfYear(cal.get(Calendar.WEEK_OF_YEAR));
this.setYear(cal.get(Calendar.YEAR));
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getDayOfYear()
*/
public int getDayOfYear()
{
return dayOfYear;
}
protected void setDayOfYear(int dayOfYear)
{
this.dayOfYear = dayOfYear;
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getDayOfMonth()
*/
public int getDayOfMonth()
{
return dayOfMonth;
}
protected void setDayOfMonth(int dayOfMonth)
{
this.dayOfMonth = dayOfMonth;
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getDayOfWeek()
*/
public int getDayOfWeek()
{
return dayOfWeek;
}
protected void setDayOfWeek(int dayOfWeek)
{
this.dayOfWeek = dayOfWeek;
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getHalfYear()
*/
public int getHalfYear()
{
return halfYear;
}
protected void setHalfYear(int halfYear)
{
this.halfYear = halfYear;
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getId()
*/
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getMonth()
*/
public int getMonth()
{
return month;
}
protected void setMonth(int month)
{
this.month = month;
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getQuarter()
*/
public int getQuarter()
{
return quarter;
}
protected void setQuarter(int quarter)
{
this.quarter = quarter;
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getWeekOfMonth()
*/
public int getWeekOfMonth()
{
return weekOfMonth;
}
protected void setWeekOfMonth(int weekOfMonth)
{
this.weekOfMonth = weekOfMonth;
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getWeekOfYear()
*/
public int getWeekOfYear()
{
return weekOfYear;
}
protected void setWeekOfYear(int weekOfYear)
{
this.weekOfYear = weekOfYear;
}
/* (non-Javadoc)
* @see org.alfresco.repo.audit.hibernate.AuditDate#getYear()
*/
public int getYear()
{
return year;
}
protected void setYear(int year)
{
this.year = year;
}
@Override
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if(!(o instanceof AuditDateImpl))
{
return false;
}
AuditDateImpl that = (AuditDateImpl)o;
return EqualsHelper.nullSafeEquals(this.date, that.date);
}
@Override
public int hashCode()
{
return this.date.hashCode();
}
/**
* Helper method to get the latest audit date
*/
public static AuditDateImpl getLatestDate(Session session)
{
Query query = session.getNamedQuery(HibernateAuditDAO.QUERY_LAST_AUDIT_DATE);
return (AuditDateImpl) query.uniqueResult();
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.hibernate;
import java.util.Date;
public interface AuditFact
{
public abstract String getArg1();
public abstract String getArg2();
public abstract String getArg3();
public abstract String getArg4();
public abstract String getArg5();
public abstract AuditConfig getAuditConfig();
public abstract AuditDate getAuditDate();
public abstract AuditSource getAuditSource();
public abstract String getClientInetAddress();
public abstract Date getDate();
public abstract String getException();
public abstract boolean isFail();
public abstract boolean isFiltered();
public abstract String getHostInetAddress();
public abstract long getId();
public abstract String getMessage();
public abstract String getNodeUUID();
public abstract String getPath();
public abstract String getReturnValue();
public abstract String getSerialisedURL();
public abstract String getSessionId();
public abstract String getStoreId();
public abstract String getStoreProtocol();
public abstract String getTransactionId();
public abstract String getUserId();
}

View File

@@ -0,0 +1,578 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.hibernate;
import java.util.Date;
/**
* An Audit fact Rely on standard equals and hash code as they should all be unique.
*
* @author Andy Hind
*/
public class AuditFactImpl implements AuditFact
{
private long id;
private AuditDate auditDate;
private AuditConfig auditConfig;
private AuditSource auditSource;
private String userId;
private Date date;
private String transactionId;
private String sessionId;
private String storeProtocol;
private String storeId;
private String nodeUUID;
private String path;
private boolean filtered;
private String returnValue;
private String arg1;
private String arg2;
private String arg3;
private String arg4;
private String arg5;
private boolean fail;
private String serialisedURL;
private String exception;
private String hostInetAddress;
private String clientInetAddress;
private String message;
public AuditFactImpl()
{
super();
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getArg1()
*/
public String getArg1()
{
return arg1;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setArg1(java.lang.String)
*/
public void setArg1(String arg1)
{
this.arg1 = arg1;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getArg2()
*/
public String getArg2()
{
return arg2;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setArg2(java.lang.String)
*/
public void setArg2(String arg2)
{
this.arg2 = arg2;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getArg3()
*/
public String getArg3()
{
return arg3;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setArg3(java.lang.String)
*/
public void setArg3(String arg3)
{
this.arg3 = arg3;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getArg4()
*/
public String getArg4()
{
return arg4;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setArg4(java.lang.String)
*/
public void setArg4(String arg4)
{
this.arg4 = arg4;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getArg5()
*/
public String getArg5()
{
return arg5;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setArg5(java.lang.String)
*/
public void setArg5(String arg5)
{
this.arg5 = arg5;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getAuditConfig()
*/
public AuditConfig getAuditConfig()
{
return auditConfig;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setAuditConfig(org.alfresco.repo.audit.hibernate.AuditConfig)
*/
public void setAuditConfig(AuditConfig auditConfig)
{
this.auditConfig = auditConfig;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getAuditDate()
*/
public AuditDate getAuditDate()
{
return auditDate;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setAuditDate(org.alfresco.repo.audit.hibernate.AuditDate)
*/
public void setAuditDate(AuditDate auditDate)
{
this.auditDate = auditDate;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getAuditSource()
*/
public AuditSource getAuditSource()
{
return auditSource;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setAuditSource(org.alfresco.repo.audit.hibernate.AuditSource)
*/
public void setAuditSource(AuditSource auditSource)
{
this.auditSource = auditSource;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getClientInetAddress()
*/
public String getClientInetAddress()
{
return clientInetAddress;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setClientInetAddress(java.net.InetAddress)
*/
public void setClientInetAddress(String clientInetAddress)
{
this.clientInetAddress = clientInetAddress;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getDate()
*/
public Date getDate()
{
return date;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setDate(java.util.Date)
*/
public void setDate(Date date)
{
this.date = date;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getException()
*/
public String getException()
{
return exception;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setException(java.lang.String)
*/
public void setException(String exception)
{
this.exception = exception;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#isFail()
*/
public boolean isFail()
{
return fail;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setFail(boolean)
*/
public void setFail(boolean fail)
{
this.fail = fail;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#isFiltered()
*/
public boolean isFiltered()
{
return filtered;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setFiltered(boolean)
*/
public void setFiltered(boolean filtered)
{
this.filtered = filtered;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getHostInetAddress()
*/
public String getHostInetAddress()
{
return hostInetAddress;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setHostInetAddress(java.net.InetAddress)
*/
public void setHostInetAddress(String hostInetAddress)
{
this.hostInetAddress = hostInetAddress;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getId()
*/
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getMessage()
*/
public String getMessage()
{
return message;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setMessage(java.lang.String)
*/
public void setMessage(String message)
{
this.message = message;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getNodeGUID()
*/
public String getNodeUUID()
{
return nodeUUID;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setNodeGUID(java.lang.String)
*/
public void setNodeUUID(String nodeUUID)
{
this.nodeUUID = nodeUUID;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getPath()
*/
public String getPath()
{
return path;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setPath(java.lang.String)
*/
public void setPath(String path)
{
this.path = path;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getReturnValue()
*/
public String getReturnValue()
{
return returnValue;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setReturnValue(java.lang.String)
*/
public void setReturnValue(String returnValue)
{
this.returnValue = returnValue;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getSerialisedURL()
*/
public String getSerialisedURL()
{
return serialisedURL;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setSerialisedURL(java.lang.String)
*/
public void setSerialisedURL(String serialisedURL)
{
this.serialisedURL = serialisedURL;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getSessionId()
*/
public String getSessionId()
{
return sessionId;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setSessionId(java.lang.String)
*/
public void setSessionId(String sessionId)
{
this.sessionId = sessionId;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getStoreId()
*/
public String getStoreId()
{
return storeId;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setStoreId(java.lang.String)
*/
public void setStoreId(String storeId)
{
this.storeId = storeId;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getStoreProtocol()
*/
public String getStoreProtocol()
{
return storeProtocol;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setStoreProtocol(java.lang.String)
*/
public void setStoreProtocol(String storeProtocol)
{
this.storeProtocol = storeProtocol;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getTransactionId()
*/
public String getTransactionId()
{
return transactionId;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setTransactionId(java.lang.String)
*/
public void setTransactionId(String transactionId)
{
this.transactionId = transactionId;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#getUserId()
*/
public String getUserId()
{
return userId;
}
/*
* (non-Javadoc)
*
* @see org.alfresco.repo.audit.hibernate.AuditFact#setUserId(java.lang.String)
*/
public void setUserId(String userId)
{
this.userId = userId;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.hibernate;
public interface AuditSource
{
public String getApplication();
public long getId();
public String getMethod();
public String getService();
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.hibernate;
import org.alfresco.util.EqualsHelper;
import org.hibernate.Query;
import org.hibernate.Session;
public class AuditSourceImpl implements AuditSource
{
/**
* The surrogate key
*/
private long id;
/**
* The auditing application (System for method audits)
*/
private String application;
/**
* The audited service
*/
private String service;
/**
* The audited method
*/
private String method;
public AuditSourceImpl()
{
super();
}
public String getApplication()
{
return application;
}
public void setApplication(String application)
{
this.application = application;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getMethod()
{
return method;
}
public void setMethod(String method)
{
this.method = method;
}
public String getService()
{
return service;
}
public void setService(String service)
{
this.service = service;
}
public static AuditSourceImpl getApplicationSource(Session session, String application)
{
Query query = session.getNamedQuery(HibernateAuditDAO.QUERY_AUDIT_APP_SOURCE);
query.setParameter(HibernateAuditDAO.QUERY_AUDIT_APP_SOURCE_APP, application);
return (AuditSourceImpl) query.uniqueResult();
}
public static AuditSourceImpl getApplicationSource(Session session, String application, String service,
String method)
{
Query query = session.getNamedQuery(HibernateAuditDAO.QUERY_AUDIT_METHOD_SOURCE);
query.setParameter(HibernateAuditDAO.QUERY_AUDIT_APP_SOURCE_APP, application);
query.setParameter(HibernateAuditDAO.QUERY_AUDIT_APP_SOURCE_SER, service);
query.setParameter(HibernateAuditDAO.QUERY_AUDIT_APP_SOURCE_MET, method);
return (AuditSourceImpl) query.uniqueResult();
}
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (!(o instanceof AuditSourceImpl))
{
return false;
}
AuditSourceImpl other = (AuditSourceImpl) o;
return EqualsHelper.nullSafeEquals(this.application, other.application)
&& EqualsHelper.nullSafeEquals(this.service, other.service)
&& EqualsHelper.nullSafeEquals(this.method, other.method);
}
@Override
public int hashCode()
{
int hash = application.hashCode();
if(service != null)
{
hash = (hash * 37) + service.hashCode();
}
if(method != null)
{
hash = (hash * 37) + method.hashCode();
}
return hash;
}
}

View File

@@ -0,0 +1,439 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.hibernate;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.audit.AuditConfiguration;
import org.alfresco.repo.audit.AuditDAO;
import org.alfresco.repo.audit.AuditInfo;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.transaction.TransactionalDao;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.datatype.Duration;
import org.alfresco.util.EqualsHelper;
import org.alfresco.util.GUID;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
/**
* Assumes mimetype and encoding sent to the content store (we are not saving this anywhere)
*
* @author Andy Hind
*/
public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO, TransactionalDao
{
public static final String QUERY_LAST_AUDIT_DATE = "audit.GetLatestAuditDate";
public static final String QUERY_LAST_AUDIT_CONFIG = "audit.GetLatestAuditConfig";
public static final String QUERY_AUDIT_APP_SOURCE = "audit.GetAuditSourceByApplication";
public static final String QUERY_AUDIT_METHOD_SOURCE = "audit.GetAuditSourceByApplicationServiceMethod";
public static final String QUERY_AUDIT_APP_SOURCE_APP = "application";
public static final String QUERY_AUDIT_APP_SOURCE_SER = "service";
public static final String QUERY_AUDIT_APP_SOURCE_MET = "method";
/** a uuid identifying this unique instance */
private String uuid;
private ContentStore contentStore;
private ThreadLocal<AuditConfiguration> auditConfiguration = new ThreadLocal<AuditConfiguration>();
private ThreadLocal<Long> auditConfigImplId = new ThreadLocal<Long>();
private ThreadLocal<Long> auditDateImplId = new ThreadLocal<Long>();
private ThreadLocal<HashMap<SourceKey, Long>> sourceIds = new ThreadLocal<HashMap<SourceKey, Long>>();
public HibernateAuditDAO()
{
super();
this.uuid = GUID.generate();
}
public ContentStore getContentStore()
{
return contentStore;
}
public void setContentStore(ContentStore contentStore)
{
this.contentStore = contentStore;
}
public void audit(AuditInfo auditInfo)
{
// Find/Build the configuraton entry
AuditConfigImpl auditConfig = getAuditConfig(auditInfo);
// Find/Build any dates
AuditDateImpl auditDate = getAuditDate(auditInfo);
// Find/Build the source
AuditSourceImpl auditSource = getAuditSource(auditInfo);
// Build the new audit fact information
AuditFactImpl auditFact = new AuditFactImpl();
auditFact.setAuditConfig(auditConfig);
auditFact.setAuditDate(auditDate);
auditFact.setAuditSource(auditSource);
// Properties
Serializable[] args = auditInfo.getMethodArguments();
if (args != null)
{
switch (args.length)
{
default:
case 5:
auditFact.setArg5(getStringOrNull(args[4]));
case 4:
auditFact.setArg4(getStringOrNull(args[3]));
case 3:
auditFact.setArg3(getStringOrNull(args[2]));
case 2:
auditFact.setArg2(getStringOrNull(args[1]));
case 1:
auditFact.setArg1(getStringOrNull(args[0]));
case 0:
}
}
auditFact.setClientInetAddress(auditInfo.getClientAddress() == null ? null : auditInfo.getClientAddress()
.toString());
auditFact.setDate(auditInfo.getDate());
auditFact.setException(auditInfo.getThrowable() == null ? null : auditInfo.getThrowable().getMessage());
auditFact.setFail(auditInfo.isFail());
auditFact.setFiltered(auditInfo.isFiltered());
auditFact.setHostInetAddress(auditInfo.getHostAddress() == null ? null : auditInfo.getHostAddress().toString());
auditFact.setMessage(auditInfo.getMessage());
auditFact.setNodeUUID(auditInfo.getKeyGUID());
auditFact.setPath(auditInfo.getPath());
auditFact.setReturnValue(auditInfo.getReturnObject() == null ? null : auditInfo.getReturnObject().toString());
// auditFact.setSerialisedURL()
auditFact.setSessionId(auditInfo.getSessionId());
if (auditInfo.getKeyStore() != null)
{
auditFact.setStoreId(auditInfo.getKeyStore().getIdentifier());
auditFact.setStoreProtocol(auditInfo.getKeyStore().getProtocol());
}
auditFact.setTransactionId(auditInfo.getTxId());
auditFact.setUserId(auditInfo.getUserIdentifier());
// Save
getSession().save(auditFact);
}
private String getStringOrNull(Object o)
{
if (o == null)
{
return null;
}
else
{
return o.toString();
}
}
private AuditSourceImpl getAuditSource(AuditInfo auditInfo)
{
AuditSourceImpl auditSourceImpl;
SourceKey sourceKey = new SourceKey(auditInfo.getAuditApplication(), auditInfo.getAuditService(), auditInfo.getAuditMethod());
if(sourceIds.get() == null)
{
sourceIds.set(new HashMap<SourceKey, Long>());
}
Long id = sourceIds.get().get(sourceKey);
if(id != null)
{
auditSourceImpl = (AuditSourceImpl) getSession().get(AuditSourceImpl.class, id.longValue());
if(auditSourceImpl != null)
{
return auditSourceImpl;
}
}
if ((auditInfo.getAuditService() != null)
&& (auditInfo.getAuditService().length() > 0) && (auditInfo.getAuditMethod() != null)
&& (auditInfo.getAuditMethod().length() > 0))
{
auditSourceImpl = AuditSourceImpl.getApplicationSource(getSession(), auditInfo.getAuditApplication(),
auditInfo.getAuditService(), auditInfo.getAuditMethod());
if (auditSourceImpl == null)
{
auditSourceImpl = new AuditSourceImpl();
auditSourceImpl.setApplication(auditInfo.getAuditApplication());
auditSourceImpl.setService(auditInfo.getAuditService());
auditSourceImpl.setMethod(auditInfo.getAuditMethod());
getSession().save(auditSourceImpl);
}
}
else
{
auditSourceImpl = AuditSourceImpl.getApplicationSource(getSession(), auditInfo.getAuditApplication());
if (auditSourceImpl == null)
{
auditSourceImpl = new AuditSourceImpl();
auditSourceImpl.setApplication(auditInfo.getAuditApplication());
getSession().save(auditSourceImpl);
}
}
sourceIds.get().put(sourceKey, Long.valueOf(auditSourceImpl.getId()));
return auditSourceImpl;
}
private AuditDateImpl getAuditDate(AuditInfo auditInfo)
{
Calendar cal = GregorianCalendar.getInstance();
cal.setTime(auditInfo.getDate());
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.HOUR_OF_DAY, 0);
Date required = cal.getTime();
AuditDateImpl auditDate;
if (auditDateImplId.get() == null)
{
auditDate = AuditDateImpl.getLatestDate(getSession());
if (auditDate == null)
{
// The first entry ever so we just make it
auditDate = new AuditDateImpl(auditInfo.getDate());
getSession().save(auditDate);
}
auditDateImplId.set(Long.valueOf(auditDate.getId()));
}
else
{
auditDate = (AuditDateImpl) getSession().get(AuditDateImpl.class, auditDateImplId.get().longValue());
if ((auditDate == null) || (!required.equals(auditDate.getDate())))
{
auditDate = AuditDateImpl.getLatestDate(getSession());
if (auditDate == null)
{
// The first entry ever so we just make it
auditDate = new AuditDateImpl(auditInfo.getDate());
getSession().save(auditDate);
}
auditDateImplId.set(Long.valueOf(auditDate.getId()));
}
}
while (!required.equals(auditDate.getDate()))
{
Date nextDate = Duration.add(auditDate.getDate(), new Duration("P1D"));
auditDate = new AuditDateImpl(nextDate);
getSession().save(auditDate);
auditDateImplId.set(Long.valueOf(auditDate.getId()));
}
return auditDate;
}
private AuditConfigImpl getAuditConfig(AuditInfo auditInfo)
{
AuditConfigImpl auditConfig;
if ((auditConfiguration.get() == null) || (auditConfiguration.get() != auditInfo.getAuditConfiguration()))
{
auditConfig = AuditConfigImpl.getLatestConfig(getSession());
if (auditConfig == null)
{
auditConfig = createNewAuditConfigImpl(auditInfo);
}
else
{
InputStream current = new BufferedInputStream(auditInfo.getAuditConfiguration().getInputStream());
ContentReader reader = contentStore.getReader(auditConfig.getConfigURL());
reader.setMimetype(MimetypeMap.MIMETYPE_XML);
reader.setEncoding("UTF-8");
InputStream last = new BufferedInputStream(reader.getContentInputStream());
int currentValue = -2;
int lastValue = -2;
try
{
while ((currentValue != -1) && (lastValue != -1) && (currentValue == lastValue))
{
currentValue = current.read();
lastValue = last.read();
}
}
catch (IOException e)
{
throw new AlfrescoRuntimeException(
"Failed to read and validate current audit configuration against the last", e);
}
if (currentValue != lastValue)
{
// Files are different - require a new entry
auditConfig = createNewAuditConfigImpl(auditInfo);
}
else
{
// No change
}
}
auditConfigImplId.set(Long.valueOf(auditConfig.getId()));
auditConfiguration.set(auditInfo.getAuditConfiguration());
}
else
{
auditConfig = (AuditConfigImpl) getSession()
.get(AuditConfigImpl.class, auditConfigImplId.get().longValue());
if (auditConfig == null)
{
auditConfig = createNewAuditConfigImpl(auditInfo);
}
}
return auditConfig;
}
private AuditConfigImpl createNewAuditConfigImpl(AuditInfo auditInfo)
{
AuditConfigImpl auditConfig = new AuditConfigImpl();
InputStream is = new BufferedInputStream(auditInfo.getAuditConfiguration().getInputStream());
String url = AbstractContentStore.createNewUrl();
ContentWriter writer = contentStore.getWriter(null, url);
writer.setMimetype(MimetypeMap.MIMETYPE_XML);
writer.setEncoding("UTF-8");
writer.putContent(is);
auditConfig.setConfigURL(url);
getSession().save(auditConfig);
return auditConfig;
}
/**
* Checks equality by type and uuid
*/
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
else if (!(obj instanceof HibernateAuditDAO))
{
return false;
}
HibernateAuditDAO that = (HibernateAuditDAO) obj;
return this.uuid.equals(that.uuid);
}
/**
* @see #uuid
*/
public int hashCode()
{
return uuid.hashCode();
}
/**
* Does this <tt>Session</tt> contain any changes which must be synchronized with the store?
*
* @return true => changes are pending
*/
public boolean isDirty()
{
// create a callback for the task
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
return session.isDirty();
}
};
// execute the callback
return ((Boolean) getHibernateTemplate().execute(callback)).booleanValue();
}
/**
* Just flushes the session
*/
public void flush()
{
getSession().flush();
}
static class SourceKey
{
String application;
String service;
String method;
SourceKey(String application, String service, String method)
{
this.application = application;
this.service = service;
this.method = method;
}
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (!(this instanceof SourceKey))
{
return false;
}
SourceKey other = (SourceKey) o;
return EqualsHelper.nullSafeEquals(this.application, other.application)
&& EqualsHelper.nullSafeEquals(this.service, other.service)
&& EqualsHelper.nullSafeEquals(this.method, other.method);
}
@Override
public int hashCode()
{
int hash = application.hashCode();
if (service != null)
{
hash = (hash * 37) + service.hashCode();
}
if (method != null)
{
hash = (hash * 37) + method.hashCode();
}
return hash;
}
}
}

View File

@@ -0,0 +1,203 @@
/*
* Copyright (C) 2005 Alfresco, Inc. Licensed under the Mozilla Public License version 1.1 with a permitted attribution clause. You may obtain a copy of the License at
* http://www.alfresco.org/legal/license.txt Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/
package org.alfresco.repo.audit.model;
import org.alfresco.repo.audit.AuditMode;
import org.alfresco.repo.audit.AuditModel;
import org.alfresco.repo.audit.PublicServiceIdentifier;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Element;
public abstract class AbstractAuditEntry
{
private static Log s_logger = LogFactory.getLog(AbstractAuditEntry.class);
private RecordOptionsImpl recordOptions = null;
private AbstractFilter filter = null;
private AuditMode auditMode = AuditMode.UNSET;
private TrueFalseUnset enabled = TrueFalseUnset.UNSET;
private TrueFalseUnset auditInternal = TrueFalseUnset.UNSET;
private AbstractAuditEntry parent;
private PublicServiceIdentifier publicServiceIdentifier;
public AbstractAuditEntry()
{
super();
}
PublicServiceIdentifier getPublicServiceIdentifier()
{
return publicServiceIdentifier;
}
public void setPublicServiceIdentifier(PublicServiceIdentifier publicServiceIdentifier)
{
this.publicServiceIdentifier = publicServiceIdentifier;
}
void configure(AbstractAuditEntry parent, Element element, NamespacePrefixResolver namespacePrefixResolver)
{
this.parent = parent;
Attribute auditModeAttribute = element.attribute(AuditModel.AT_MODE);
if (auditModeAttribute != null)
{
auditMode = AuditMode.getAuditMode(auditModeAttribute.getValue());
}
if(s_logger.isDebugEnabled())
{
s_logger.debug("Audit Mode = "+auditMode);
}
Attribute enabledAttribute = element.attribute(AuditModel.AT_ENABLED);
if (enabledAttribute != null)
{
enabled = TrueFalseUnset.getTrueFalseUnset(enabledAttribute.getValue());
}
if(s_logger.isDebugEnabled())
{
s_logger.debug("Enabled = "+enabled);
}
Attribute auditInternalAttribute = element.attribute(AuditModel.AT_AUDIT_INTERNAL);
if (auditInternalAttribute != null)
{
auditInternal = TrueFalseUnset.getTrueFalseUnset(auditInternalAttribute.getValue());
}
if(s_logger.isDebugEnabled())
{
s_logger.debug("Audit Internal = "+auditInternal);
}
// Make record options
Element recordOptionElement = element.element(AuditModel.EL_RECORD_OPTIONS);
if (recordOptionElement != null)
{
recordOptions = new RecordOptionsImpl();
recordOptions.configure(recordOptionElement, namespacePrefixResolver);
}
if(s_logger.isDebugEnabled())
{
s_logger.debug("Record Options = "+recordOptions);
}
// Make filters
Element filterElement = element.element(AuditModel.EL_FILTER);
if (filterElement != null)
{
filter = AbstractFilter.createFilter(filterElement, namespacePrefixResolver);
}
if(s_logger.isDebugEnabled())
{
s_logger.debug("Filter = "+filter);
}
}
/* package */TrueFalseUnset getAuditInternal()
{
return auditInternal;
}
/* package */AuditMode getAuditMode()
{
return auditMode;
}
/* package */TrueFalseUnset getEnabled()
{
return enabled;
}
/* package */AbstractFilter getFilter()
{
return filter;
}
/* package */AbstractAuditEntry getParent()
{
return parent;
}
/* package */RecordOptionsImpl getRecordOptions()
{
return recordOptions;
}
protected AuditMode getEffectiveAuditMode()
{
AuditMode auditMode;
if (checkEnabled() == TrueFalseUnset.TRUE)
{
auditMode = getAuditModeOrParentAuditMode();
}
else
{
auditMode = AuditMode.NONE;
}
if(s_logger.isDebugEnabled())
{
s_logger.debug("... Effective audit mode is = "+auditMode);
}
return auditMode;
}
private AuditMode getAuditModeOrParentAuditMode()
{
AuditMode auditMode = getAuditMode();
if(s_logger.isDebugEnabled())
{
s_logger.debug("... ... audit mode is = "+auditMode);
}
if (auditMode == AuditMode.UNSET)
{
if (getParent() == null)
{
return AuditMode.UNSET;
}
else
{
return getParent().getAuditModeOrParentAuditMode();
}
}
else
{
return auditMode;
}
}
private TrueFalseUnset checkEnabled()
{
TrueFalseUnset effective = getEnabled();
if (getParent() != null)
{
if ((getParent().checkEnabled() == TrueFalseUnset.TRUE) && (effective != TrueFalseUnset.FALSE))
{
return TrueFalseUnset.TRUE;
}
}
else
{
if (effective == TrueFalseUnset.TRUE)
{
return TrueFalseUnset.TRUE;
}
}
return TrueFalseUnset.FALSE;
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import org.alfresco.repo.audit.AuditModel;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Element;
/**
* The base class for filtering.
*
* This supports negating the filter, ie NOT.
*
* @author Andy Hind
*/
public abstract class AbstractFilter implements XMLModelElement
{
private static Log s_logger = LogFactory.getLog(AbstractFilter.class);
private boolean invert = false;
public AbstractFilter()
{
super();
}
public static AbstractFilter createFilter(Element filterElement, NamespacePrefixResolver namespacePrefixResolver)
{
AbstractFilter filter;
Attribute typeAttribute = filterElement.attribute(AuditModel.AT_TYPE);
if (typeAttribute == null)
{
throw new AuditModelException("A filter must specify it concrete type using xsi:type");
}
if (typeAttribute.getStringValue().endsWith("FilterSet"))
{
filter = new FilterSet();
}
else if (typeAttribute.getStringValue().endsWith("KeyFilter"))
{
filter = new KeyFilter();
}
else if (typeAttribute.getStringValue().endsWith("ParameterFilter"))
{
filter = new ParameterFilter();
}
else
{
throw new AuditModelException(
"Invalid filter type. It must be one of: FilterSet, KeyFilter, ParameterFilter ");
}
filter.configure(filterElement, namespacePrefixResolver);
return filter;
}
public void configure(Element element, NamespacePrefixResolver namespacePrefixResolver)
{
Attribute invertAttribute = element.attribute(AuditModel.AT_INVERT);
if (invertAttribute != null)
{
invert = Boolean.valueOf(invertAttribute.getStringValue()).booleanValue();
}
else
{
invert = false;
}
}
/* package */boolean isInvert()
{
return invert;
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import org.alfresco.repo.audit.AuditModel;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Element;
public abstract class AbstractNamedAuditEntry extends AbstractAuditEntry
{
private static Log s_logger = LogFactory.getLog(AbstractNamedAuditEntry.class);
private String name;
public AbstractNamedAuditEntry()
{
super();
}
@Override
void configure(AbstractAuditEntry parent, Element element, NamespacePrefixResolver namespacePrefixResolver)
{
Attribute nameAttribute = element.attribute(AuditModel.AT_NAME);
if (nameAttribute != null)
{
name = nameAttribute.getStringValue();
}
else
{
throw new AuditModelException("The name attribute is mandatory");
}
if(s_logger.isDebugEnabled())
{
s_logger.debug("Name = "+name);
}
super.configure(parent, element, namespacePrefixResolver);
}
/* package */String getName()
{
return name;
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import org.alfresco.repo.audit.ApplicationAuditModel;
import org.alfresco.repo.audit.AuditMode;
import org.alfresco.repo.audit.RecordOptions;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ApplicationAuditEntry extends AbstractNamedAuditEntry implements ApplicationAuditModel
{
private static Log s_logger = LogFactory.getLog(ApplicationAuditEntry.class);
public ApplicationAuditEntry()
{
super();
}
public AuditMode beforeExecution(AuditMode auditMode, String application, String description, NodeRef key, Object... args)
{
if(s_logger.isDebugEnabled())
{
s_logger.debug("Evaluating if application is audited ..."+application);
}
return getEffectiveAuditMode();
}
public AuditMode afterExecution(AuditMode auditMode, String application, String description, NodeRef key, Object... args)
{
throw new UnsupportedOperationException();
}
public AuditMode onError(AuditMode auditMode, String application, String description, NodeRef key, Object... args)
{
throw new UnsupportedOperationException();
}
public RecordOptions getAuditRecordOptions(String application)
{
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,220 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.alfresco.repo.audit.AuditConfiguration;
import org.alfresco.repo.audit.AuditMode;
import org.alfresco.repo.audit.AuditModel;
import org.alfresco.repo.audit.RecordOptions;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.InitializingBean;
public class AuditEntry extends AbstractAuditEntry implements InitializingBean, AuditModel
{
private static Log s_logger = LogFactory.getLog(AuditEntry.class);
private Map<String, ServiceAuditEntry> services = new HashMap<String, ServiceAuditEntry>();
private Map<String, ApplicationAuditEntry> applications = new HashMap<String, ApplicationAuditEntry>();
private AuditConfiguration auditConfiguration;
private NamespacePrefixResolver namespacePrefixResolver;
public AuditEntry()
{
super();
}
public AuditConfiguration getAuditConfiguration()
{
return auditConfiguration;
}
public void setAuditConfiguration(AuditConfiguration auditConfiguration)
{
this.auditConfiguration = auditConfiguration;
}
public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver)
{
this.namespacePrefixResolver = namespacePrefixResolver;
}
public void afterPropertiesSet() throws Exception
{
Document document = createDocument();
Element root = document.getRootElement();
// Check it is the correct thing
configure(null, root, namespacePrefixResolver);
}
@Override
void configure(AbstractAuditEntry parent, Element element, NamespacePrefixResolver namespacePrefixResolver)
{
if (!element.getNamespaceURI().equals(AuditModel.NAME_SPACE))
{
throw new AuditModelException("Audit model has incorrect name space");
}
if (!element.getName().equals(AuditModel.EL_AUDIT))
{
throw new AuditModelException("Audit model has incorrect root node");
}
if(s_logger.isDebugEnabled())
{
s_logger.debug("Audit configuration");
}
super.configure(parent, element, namespacePrefixResolver);
// Add services
if(s_logger.isDebugEnabled())
{
s_logger.debug("Adding services ...");
}
for (Iterator nsit = element.elementIterator(AuditModel.EL_SERVICE); nsit.hasNext(); /**/)
{
Element serviceElement = (Element) nsit.next();
ServiceAuditEntry service = new ServiceAuditEntry();
service.configure(this, serviceElement, namespacePrefixResolver);
services.put(service.getName(), service);
}
// Add Applications
if(s_logger.isDebugEnabled())
{
s_logger.debug("Adding applications ...");
}
for (Iterator nsit = element.elementIterator(AuditModel.EL_APPLICATION); nsit.hasNext(); /**/)
{
Element applicationElement = (Element) nsit.next();
ApplicationAuditEntry application = new ApplicationAuditEntry();
application.configure(this, applicationElement, namespacePrefixResolver);
applications.put(application.getName(), application);
}
}
public AuditMode beforeExecution(AuditMode auditMode, MethodInvocation mi)
{
String serviceName = getPublicServiceIdentifier().getPublicServiceName(mi);
ServiceAuditEntry service = services.get(serviceName);
if(service != null)
{
return service.beforeExecution(auditMode, mi);
}
else
{
if(s_logger.isDebugEnabled())
{
s_logger.debug("No specific audit entry for service "+serviceName);
}
return getEffectiveAuditMode();
}
}
public AuditMode afterExecution(AuditMode auditMode, MethodInvocation mi)
{
throw new UnsupportedOperationException();
}
public RecordOptions getAuditRecordOptions(MethodInvocation mi)
{
throw new UnsupportedOperationException();
}
public AuditMode onError(AuditMode auditMode, MethodInvocation mi)
{
throw new UnsupportedOperationException();
}
private Document createDocument()
{
InputStream is = auditConfiguration.getInputStream();
if (is == null)
{
throw new AuditModelException("Audit configuration could not be opened");
}
SAXReader reader = new SAXReader();
try
{
Document document = reader.read(is);
is.close();
return document;
}
catch (DocumentException e)
{
throw new AuditModelException("Failed to create audit model document ", e);
}
catch (IOException e)
{
throw new AuditModelException("Failed to close audit model document ", e);
}
}
public AuditMode beforeExecution(AuditMode auditMode, String application, String description, NodeRef key, Object... args)
{
ApplicationAuditEntry aae = applications.get(application);
if(aae != null)
{
return aae.beforeExecution(auditMode, application, description, key, args);
}
else
{
if(s_logger.isDebugEnabled())
{
s_logger.debug("No specific audit entry for application "+application);
}
return getEffectiveAuditMode();
}
}
public AuditMode afterExecution(AuditMode auditMode, String application, String description, NodeRef key, Object... args)
{
throw new UnsupportedOperationException();
}
public AuditMode onError(AuditMode auditMode, String application, String description, NodeRef key, Object... args)
{
throw new UnsupportedOperationException();
}
public RecordOptions getAuditRecordOptions(String application)
{
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import org.alfresco.error.AlfrescoRuntimeException;
/**
* Exceptions from the audit model package.
*
* @author Andy Hind
*/
public class AuditModelException extends AlfrescoRuntimeException
{
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = -2527034441058184109L;
public AuditModelException(String msgId)
{
super(msgId);
}
public AuditModelException(String msgId, Object[] msgParams)
{
super(msgId, msgParams);
}
public AuditModelException(String msgId, Throwable cause)
{
super(msgId, cause);
}
public AuditModelException(String msgId, Object[] msgParams, Throwable cause)
{
super(msgId, msgParams, cause);
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.alfresco.repo.audit.AuditModel;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Element;
/**
* This groups a set of filters together using AND or OR. They are evaluated in definition order with short cut evaluation if possible. The default beahviour is to or Filters
* together.
*
* @author Andy Hind
*/
public class FilterSet extends AbstractFilter implements XMLModelElement
{
private static Log s_logger = LogFactory.getLog(FilterSet.class);
private List<AbstractFilter> filters = new ArrayList<AbstractFilter>();
private FilterSetMode mode = FilterSetMode.OR;
public FilterSet()
{
super();
}
@Override
public void configure(Element element, NamespacePrefixResolver namespacePrefixResolver)
{
super.configure(element, namespacePrefixResolver);
// Mode
Attribute modeAttribute = element.attribute(AuditModel.AT_MODE);
if (modeAttribute != null)
{
mode = FilterSetMode.getFilterSetMode(modeAttribute.getStringValue());
}
// Filters
for (Iterator nsit = element.elementIterator(AuditModel.EL_FILTER); nsit.hasNext(); /**/)
{
Element filterElement = (Element) nsit.next();
AbstractFilter filter = AbstractFilter.createFilter(filterElement, namespacePrefixResolver);
filters.add(filter);
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
/**
* The enum to define if elements of a filter set are combined using AND or OR.
*
* @author Andy Hind
*/
public enum FilterSetMode
{
AND, OR;
public static FilterSetMode getFilterSetMode(String value)
{
if(value.equalsIgnoreCase("or"))
{
return FilterSetMode.OR;
}
else if(value.equalsIgnoreCase("or"))
{
return FilterSetMode.AND;
}
else
{
throw new AuditModelException("Invalid FilterSetMode: "+value);
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import org.alfresco.repo.audit.AuditModel;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Element;
public class KeyFilter extends AbstractFilter
{
private static Log s_logger = LogFactory.getLog(KeyFilter.class);
private String expression;
private KeyFilterMode keyFilterMode;
public KeyFilter()
{
super();
}
@Override
public void configure(Element element, NamespacePrefixResolver namespacePrefixResolver)
{
super.configure(element, namespacePrefixResolver);
// Filter mode
Attribute keyFilterTypeAttribute = element.attribute(AuditModel.AT_MODE);
if(keyFilterTypeAttribute != null)
{
keyFilterMode = KeyFilterMode.getKeyFilterMode(keyFilterTypeAttribute.getStringValue());
}
else
{
keyFilterMode = KeyFilterMode.ALL;
}
// Expression
Element expressionElement = element.element(AuditModel.EL_EXPRESSION);
if(expressionElement == null)
{
throw new AuditModelException("An expression is mandatory for a key filter");
}
else
{
expression = expressionElement.getText();
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
/**
* This enum defines the type of restriction to apply to filter based on the key node ref.
*
* This restriction can be based upon:
*
* <ol>
* <li> The path to the node
* <li> The type of the node
* <li> The presence of an aspect
* <li> The NodeRef of the node
* <li> An XPATH expression evaluated in the context of the node with the return tested for the node.
* e.g. ".[@cm:content = 'woof']"
* <li> A simple value for equality tests given a non node argument
* <li> The protocol of the store containing the node
* <li> The identifier of the store containing the node
* <li> Or no restriction
* </ol>
*
* @author Andy Hind
*/
public enum KeyFilterMode
{
PATH, TYPE, ASPECT, NODE_REF, ALL, XPATH, VALUE, STORE_PROTOCOL, STORE_IDENTIFIER;
public static KeyFilterMode getKeyFilterMode(String value)
{
if(value.equalsIgnoreCase("path"))
{
return KeyFilterMode.PATH;
}
else if(value.equalsIgnoreCase("type"))
{
return KeyFilterMode.TYPE;
}
else if(value.equalsIgnoreCase("aspect"))
{
return KeyFilterMode.ASPECT;
}
else if(value.equalsIgnoreCase("node_ref"))
{
return KeyFilterMode.NODE_REF;
}
else if(value.equalsIgnoreCase("all"))
{
return KeyFilterMode.ALL;
}
else if(value.equalsIgnoreCase("xpath"))
{
return KeyFilterMode.XPATH;
}
else if(value.equalsIgnoreCase("value"))
{
return KeyFilterMode.VALUE;
}
else if(value.equalsIgnoreCase("store_protocol"))
{
return KeyFilterMode.STORE_PROTOCOL;
}
else if(value.equalsIgnoreCase("store_identifier"))
{
return KeyFilterMode.STORE_IDENTIFIER;
}
else
{
throw new AuditModelException("Unknown KeyFilterMode: "+value);
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import org.alfresco.repo.audit.AuditMode;
import org.alfresco.repo.audit.MethodAuditModel;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MethodAuditEntry extends AbstractNamedAuditEntry implements MethodAuditModel
{
private static Log s_logger = LogFactory.getLog(MethodAuditEntry.class);
public MethodAuditEntry()
{
super();
// TODO Auto-generated constructor stub
}
public AuditMode beforeExecution(AuditMode auditMode, MethodInvocation mi)
{
if(s_logger.isDebugEnabled())
{
s_logger.debug("Evaluating if method is audited ..."+((ServiceAuditEntry)getParent()).getName()+"."+getName());
}
return getEffectiveAuditMode();
}
public AuditMode afterExecution(AuditMode auditMode, MethodInvocation mi)
{
throw new UnsupportedOperationException();
}
public AuditMode onError(AuditMode auditMode, MethodInvocation mi)
{
throw new UnsupportedOperationException();
}
public RecordOptionsImpl getAuditRecordOptions(MethodInvocation mi)
{
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import org.alfresco.repo.audit.AuditModel;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Element;
public class ParameterFilter extends KeyFilter implements XMLModelElement
{
private static Log s_logger = LogFactory.getLog(ParameterFilter.class);
private QName parameterName;
public ParameterFilter()
{
super();
}
@Override
public void configure(Element element, NamespacePrefixResolver namespacePrefixResolver)
{
super.configure(element, namespacePrefixResolver);
Element parameterNameElement = element.element(AuditModel.EL_PARAMETER_NAME);
if(parameterNameElement == null)
{
throw new AuditModelException("A parameter is mandatory for a parameter filter");
}
else
{
String stringQName = parameterNameElement.getStringValue();
if (stringQName.charAt(1) == '{')
{
parameterName = QName.createQName(stringQName);
}
else
{
parameterName = QName.createQName(stringQName);
}
}
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import org.alfresco.repo.audit.AuditModel;
import org.alfresco.repo.audit.RecordOptions;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Element;
public class RecordOptionsImpl implements XMLModelElement, RecordOptions
{
private static Log s_logger = LogFactory.getLog(RecordOptionsImpl.class);
private TrueFalseUnset recordPath = TrueFalseUnset.UNSET;
private TrueFalseUnset recordFilters = TrueFalseUnset.UNSET;
private TrueFalseUnset recordSerializedReturnValue = TrueFalseUnset.UNSET;
private TrueFalseUnset recordSerializedExceptions = TrueFalseUnset.UNSET;
private TrueFalseUnset recordSerializedMethodArguments = TrueFalseUnset.UNSET;
private TrueFalseUnset recordSerializedKeyPropertiesBeforeEvaluation = TrueFalseUnset.UNSET;
private TrueFalseUnset recordSerializedKeyPropertiesAfterEvaluation = TrueFalseUnset.UNSET;
public RecordOptionsImpl()
{
super();
}
public static RecordOptionsImpl mergeRecordOptions(RecordOptions primary, RecordOptions secondary)
{
RecordOptionsImpl answer = new RecordOptionsImpl();
setOptions(answer, primary, true);
setOptions(answer, secondary, false);
return answer;
}
private static void setOptions(RecordOptionsImpl on, RecordOptions from, boolean force)
{
if(force || on.recordFilters.equals( TrueFalseUnset.UNSET))
{
on.recordFilters = from.getRecordFilters();
}
if(force || on.recordPath.equals( TrueFalseUnset.UNSET))
{
on.recordPath = from.getRecordPath();
}
if(force || on.recordSerializedExceptions.equals( TrueFalseUnset.UNSET))
{
on.recordSerializedExceptions = from.getRecordSerializedExceptions();
}
if(force || on.recordSerializedKeyPropertiesAfterEvaluation.equals( TrueFalseUnset.UNSET))
{
on.recordSerializedKeyPropertiesAfterEvaluation = from.getRecordSerializedKeyPropertiesAfterEvaluation();
}
if(force || on.recordSerializedKeyPropertiesBeforeEvaluation.equals( TrueFalseUnset.UNSET))
{
on.recordSerializedKeyPropertiesBeforeEvaluation = from.getRecordSerializedKeyPropertiesBeforeEvaluation();
}
if(force || on.recordSerializedMethodArguments.equals( TrueFalseUnset.UNSET))
{
on.recordSerializedMethodArguments = from.getRecordSerializedMethodArguments();
}
if(force || on.recordSerializedReturnValue.equals( TrueFalseUnset.UNSET))
{
on.recordSerializedReturnValue = from.getRecordSerializedReturnValue();
}
}
public TrueFalseUnset getRecordFilters()
{
return recordFilters;
}
public TrueFalseUnset getRecordPath()
{
return recordPath;
}
public TrueFalseUnset getRecordSerializedExceptions()
{
return recordSerializedExceptions;
}
public TrueFalseUnset getRecordSerializedKeyPropertiesAfterEvaluation()
{
return recordSerializedKeyPropertiesAfterEvaluation;
}
public TrueFalseUnset getRecordSerializedKeyPropertiesBeforeEvaluation()
{
return recordSerializedKeyPropertiesBeforeEvaluation;
}
public TrueFalseUnset getRecordSerializedMethodArguments()
{
return recordSerializedMethodArguments;
}
public TrueFalseUnset getRecordSerializedReturnValue()
{
return recordSerializedReturnValue;
}
public void configure(Element recordOptionElement, NamespacePrefixResolver namespacePrefixResolver)
{
Element recordFiltersElement = recordOptionElement.element(AuditModel.EL_RECORD_FILTERS);
if (recordFiltersElement != null)
{
recordFilters = TrueFalseUnset.getTrueFalseUnset(recordFiltersElement.getStringValue());
}
Element recordPathElement = recordOptionElement.element(AuditModel.EL_RECORD_PATH);
if (recordPathElement != null)
{
recordPath = TrueFalseUnset.getTrueFalseUnset(recordPathElement.getStringValue());
}
Element recordSerAgrsElement = recordOptionElement.element(AuditModel.EL_RECORD_SER_ARGS);
if (recordSerAgrsElement != null)
{
recordSerializedMethodArguments = TrueFalseUnset.getTrueFalseUnset(recordSerAgrsElement.getStringValue());
}
Element recordSerExElement = recordOptionElement.element(AuditModel.EL_RECORD_SER_EX);
if (recordSerExElement != null)
{
recordSerializedExceptions = TrueFalseUnset.getTrueFalseUnset(recordSerExElement.getStringValue());
}
Element recordSerPropAfterElement = recordOptionElement.element(AuditModel.EL_RECORD_SER_PROP_AFTER);
if (recordSerPropAfterElement != null)
{
recordSerializedKeyPropertiesAfterEvaluation = TrueFalseUnset.getTrueFalseUnset(recordSerPropAfterElement
.getStringValue());
}
Element recordSerPropBeforeElement = recordOptionElement.element(AuditModel.EL_RECORD_SER_PROP_BEFORE);
if (recordSerPropBeforeElement != null)
{
recordSerializedKeyPropertiesBeforeEvaluation = TrueFalseUnset.getTrueFalseUnset(recordSerPropBeforeElement
.getStringValue());
}
Element recordSerRetElement = recordOptionElement.element(AuditModel.EL_RECORD_SER_RETURN_VAL);
if (recordSerRetElement != null)
{
recordSerializedReturnValue = TrueFalseUnset.getTrueFalseUnset(recordSerRetElement.getStringValue());
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("Record Options(");
builder.append("Filters=").append(getRecordFilters());
builder.append(",Path=").append(getRecordPath());
builder.append(",Exception=").append(getRecordSerializedExceptions());
builder.append(",PropertiesBefore=").append(getRecordSerializedKeyPropertiesAfterEvaluation());
builder.append(",PropertiesAfter=").append(getRecordSerializedKeyPropertiesBeforeEvaluation());
builder.append(",Args=").append(getRecordSerializedMethodArguments());
builder.append(",Return=").append(getRecordSerializedReturnValue());
builder.append(")");
return builder.toString();
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.alfresco.repo.audit.AuditMode;
import org.alfresco.repo.audit.AuditModel;
import org.alfresco.repo.audit.MethodAuditModel;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Element;
public class ServiceAuditEntry extends AbstractNamedAuditEntry implements MethodAuditModel
{
private static Log s_logger = LogFactory.getLog(ServiceAuditEntry.class);
private Map<String, MethodAuditEntry> methods = new HashMap<String, MethodAuditEntry>();
public ServiceAuditEntry()
{
super();
}
@Override
void configure(AbstractAuditEntry parent, Element element, NamespacePrefixResolver namespacePrefixResolver)
{
super.configure(parent, element, namespacePrefixResolver);
// Add Methods
if(s_logger.isDebugEnabled())
{
s_logger.debug("Adding methods to service "+getName());
}
for (Iterator nsit = element.elementIterator(AuditModel.EL_METHOD); nsit.hasNext(); /**/)
{
Element methodElement = (Element) nsit.next();
MethodAuditEntry method = new MethodAuditEntry();
method.configure(this, methodElement, namespacePrefixResolver);
methods.put(method.getName(), method);
}
if(s_logger.isDebugEnabled())
{
s_logger.debug("...added methods for service "+getName());
}
}
public AuditMode beforeExecution(AuditMode auditMode, MethodInvocation mi)
{
String methodName = mi.getMethod().getName();
MethodAuditEntry method = methods.get(methodName);
if (method != null)
{
return method.beforeExecution(auditMode, mi);
}
else
{
if(s_logger.isDebugEnabled())
{
s_logger.debug("Evaluating if service is audited (no specific setting) for "+getName()+"."+methodName);
}
return getEffectiveAuditMode();
}
}
public AuditMode afterExecution(AuditMode auditMode, MethodInvocation mi)
{
throw new UnsupportedOperationException();
}
public AuditMode onError(AuditMode auditMode, MethodInvocation mi)
{
throw new UnsupportedOperationException();
}
public RecordOptionsImpl getAuditRecordOptions(MethodInvocation mi)
{
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
/**
* An enum for the values
* <ol>
* <li> TRUE
* <li> FALSE
* <li> UNSET
* </ol>
*
* @author Andy Hind
*/
public enum TrueFalseUnset
{
TRUE, FALSE, UNSET;
public static TrueFalseUnset getTrueFalseUnset(String value)
{
if(value.equalsIgnoreCase("true"))
{
return TrueFalseUnset.TRUE;
}
else if(value.equalsIgnoreCase("false"))
{
return TrueFalseUnset.FALSE;
}
else if(value.equalsIgnoreCase("unset"))
{
return TrueFalseUnset.UNSET;
}
else
{
throw new AuditModelException("Invalid value for TrueFalseUnset: "+value);
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.audit.model;
import org.alfresco.service.namespace.NamespacePrefixResolver;
import org.dom4j.Element;
public interface XMLModelElement
{
void configure(Element element, NamespacePrefixResolver namespacePrefixResolver );
}

View File

@@ -100,13 +100,6 @@ public class EhCacheAdapter<K extends Serializable, V extends Serializable>
public void clear()
{
try
{
cache.removeAll();
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Failed to clear cache", e);
}
cache.removeAll();
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.cache;
import java.io.IOException;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
/**
* This is virtually a copy of the Springframework version, with the exception
* that it uses the newer constructors for the <code>EHCacheManager</code>
* instances.
*
* @author Derek Hulley
*/
public class EhCacheManagerFactoryBean implements FactoryBean, InitializingBean, DisposableBean
{
protected final Log logger = LogFactory.getLog(EhCacheManagerFactoryBean.class);
private Resource configLocation;
private CacheManager cacheManager;
/**
*
* @param configLocation a resource location using the <b>file:</b> or <b>classpath:</b> prefix
*/
public void setConfigLocation(Resource configLocation)
{
this.configLocation = configLocation;
}
public void afterPropertiesSet() throws IOException, CacheException
{
PropertyCheck.mandatory(this, "configLocation", configLocation);
logger.info("Initializing EHCache CacheManager");
this.cacheManager = new CacheManager(this.configLocation.getURL());
}
public Object getObject()
{
return this.cacheManager;
}
public Class getObjectType()
{
return (this.cacheManager != null ? this.cacheManager.getClass() : CacheManager.class);
}
public boolean isSingleton()
{
return true;
}
public void destroy()
{
logger.info("Shutting down EHCache CacheManager");
this.cacheManager.shutdown();
}
}

View File

@@ -16,7 +16,6 @@
*/
package org.alfresco.repo.cache;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
@@ -438,15 +437,8 @@ public class TransactionalCache<K extends Serializable, V extends Serializable>
// and also serves to ensure that the shared cache will be ignored
// for the remainder of the transaction
txnData.isClearOn = true;
try
{
txnData.updatedItemsCache.removeAll();
txnData.removedItemsCache.removeAll();
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Failed to clear caches", e);
}
txnData.updatedItemsCache.removeAll();
txnData.removedItemsCache.removeAll();
}
else // no transaction
{

View File

@@ -29,7 +29,6 @@ import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.poi.poifs.eventfilesystem.POIFSReader;
import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
@@ -130,7 +129,8 @@ public class MailMetadataExtracter extends AbstractMetadataExtracter
private static final String ENCODING_UNICODE = "001F";
private static final String SUBSTG_MESSAGEBODY = "1000";
private static final String SUBSTG_RECIPIENTEMAIL = "39FE";
private static final String SUBSTG_RECIPIENTEMAIL = "39FE"; // 7bit email address
private static final String SUBSTG_RECIPIENTSEARCH = "300B"; // address 'search' variant
private static final String SUBSTG_RECEIVEDEMAIL = "0076";
private static final String SUBSTG_SENDEREMAIL = "0C1F";
private static final String SUBSTG_DATE = "0047";
@@ -159,6 +159,27 @@ public class MailMetadataExtracter extends AbstractMetadataExtracter
{
receipientEmails.get().add(convertExchangeAddress(extractText()));
}
else if (type.equals(SUBSTG_RECIPIENTSEARCH))
{
String email = extractText(ENCODING_TEXT);
int smptIndex = email.indexOf("SMTP:");
if (smptIndex != -1)
{
/* also may be used for SUBSTG_RECIPIENTTRANSPORT = "5FF7";
with search for SMPT followed by a null char */
// this is a secondary mechanism for encoding a receipient email address
// the 7 bit email address may not have been set by Outlook - so this is needed instead
// handle null character at end of string
int endIndex = email.length();
if (email.codePointAt(email.length() - 1) == 0)
{
endIndex--;
}
email = email.substring(smptIndex + 5, endIndex);
receipientEmails.get().add(email);
}
}
else if (type.equals(SUBSTG_RECEIVEDEMAIL))
{
destination.put(ContentModel.PROP_ADDRESSEE, convertExchangeAddress(extractText()));
@@ -169,8 +190,8 @@ public class MailMetadataExtracter extends AbstractMetadataExtracter
}
else if (type.equals(SUBSTG_DATE))
{
// the date is not really plain text - but it's easier to parse as such
String date = extractText();
// the date is not "really" plain text - but it's appropriate to parse as such
String date = extractText(ENCODING_TEXT);
int valueIndex = date.indexOf("l=");
if (valueIndex != -1)
{
@@ -203,15 +224,28 @@ public class MailMetadataExtracter extends AbstractMetadataExtracter
*/
private String extractText()
throws IOException
{
return extractText(this.encoding);
}
/**
* Extract the text from the stream based on the encoding
*
* @return String
*
* @throws IOException
*/
private String extractText(String encoding)
throws IOException
{
byte[] data = new byte[stream.available()];
stream.read(data);
if (this.encoding.equals(ENCODING_TEXT) || this.encoding.equals(ENCODING_BINARY))
if (encoding.equals(ENCODING_TEXT) || encoding.equals(ENCODING_BINARY))
{
return new String(data);
}
else if (this.encoding.equals(ENCODING_UNICODE))
else if (encoding.equals(ENCODING_UNICODE))
{
// convert double-byte encoding to single byte for String conversion
byte[] b = new byte[data.length >> 1];

View File

@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.policy.ClassPolicyDelegate;
import org.alfresco.repo.policy.JavaBehaviour;
@@ -31,6 +32,7 @@ import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.PolicyScope;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
@@ -401,6 +403,23 @@ public class CopyServiceImpl implements CopyService
}
}
// if the parent node is the same, then remove the name property - it will have to
// be changed by the client code
AssociationDefinition assocDef = dictionaryService.getAssociation(destinationAssocTypeQName);
if (!assocDef.isChild())
{
throw new AlfrescoRuntimeException("Association is not a child association: " + destinationAssocTypeQName);
}
else
{
ChildAssociationDefinition childAssocDef = (ChildAssociationDefinition) assocDef;
if (!childAssocDef.getDuplicateChildNamesAllowed())
{
// duplicate children are not allowed.
properties.remove(ContentModel.PROP_NAME);
}
}
// Create the new node
ChildAssociationRef destinationChildAssocRef = this.nodeService.createNode(
destinationParent,

View File

@@ -41,9 +41,9 @@ public interface NodeStatus
public void setNode(Node node);
public String getChangeTxnId();
public Transaction getTransaction();
public void setChangeTxnId(String txnId);
public void setTransaction(Transaction transaction);
public boolean isDeleted();
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.domain;
/**
* Interface for persistent <b>server</b> objects. These persist
* details of the servers that have committed transactions to the
* database, for instance.
*
* @author Derek Hulley
*/
public interface Server
{
public Long getId();
public String getIpAddress();
public void setIpAddress(String ipAddress);
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.domain;
/**
* Interface for persistent <b>transaction</b> objects.
*
* @author Derek Hulley
*/
public interface Transaction
{
public Long getId();
public String getChangeTxnId();
public void setChangeTxnId(String changeTxnId);
public Server getServer();
public void setServer(Server server);
}

View File

@@ -31,8 +31,10 @@ import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.NodeKey;
import org.alfresco.repo.domain.NodeStatus;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.domain.Server;
import org.alfresco.repo.domain.Store;
import org.alfresco.repo.domain.StoreKey;
import org.alfresco.repo.domain.Transaction;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -53,8 +55,11 @@ import org.hibernate.exception.ConstraintViolationException;
public class HibernateNodeTest extends BaseSpringTest
{
private static final String TEST_NAMESPACE = "http://www.alfresco.org/test/HibernateNodeTest";
private static int i = 0;
private Store store;
private Server server;
private Transaction transaction;
public HibernateNodeTest()
{
@@ -68,6 +73,18 @@ public class HibernateNodeTest extends BaseSpringTest
store.setKey(storeKey);
// persist so that it is present in the hibernate cache
getSession().save(store);
server = (Server) getSession().get(ServerImpl.class, new Long(1));
if (server == null)
{
server = new ServerImpl();
server.setIpAddress("" + "i_" + System.currentTimeMillis());
getSession().save(server);
}
transaction = new TransactionImpl();
transaction.setServer(server);
transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
getSession().save(transaction);
}
protected void onTearDownInTransaction()
@@ -108,7 +125,7 @@ public class HibernateNodeTest extends BaseSpringTest
// create the node status
NodeStatus nodeStatus = new NodeStatusImpl();
nodeStatus.setKey(key);
nodeStatus.setChangeTxnId("txn:123");
nodeStatus.setTransaction(transaction);
getSession().save(nodeStatus);
// create a new Node
@@ -131,7 +148,7 @@ public class HibernateNodeTest extends BaseSpringTest
node = nodeStatus.getNode();
assertNotNull("Node was not attached to status", node);
// change the values
nodeStatus.setChangeTxnId("txn:456");
transaction.setChangeTxnId("txn:456");
// delete the node
getSession().delete(node);
@@ -351,7 +368,7 @@ public class HibernateNodeTest extends BaseSpringTest
NodeStatus containerNodeStatus = new NodeStatusImpl();
containerNodeStatus.setKey(containerNodeKey);
containerNodeStatus.setNode(containerNode);
containerNodeStatus.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
containerNodeStatus.setTransaction(transaction);
getSession().save(containerNodeStatus);
// make content node 1
Node contentNode1 = new NodeImpl();
@@ -366,7 +383,7 @@ public class HibernateNodeTest extends BaseSpringTest
NodeStatus contentNodeStatus1 = new NodeStatusImpl();
contentNodeStatus1.setKey(contentNodeKey1);
contentNodeStatus1.setNode(contentNode1);
contentNodeStatus1.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
contentNodeStatus1.setTransaction(transaction);
getSession().save(contentNodeStatus1);
// make content node 2
Node contentNode2 = new NodeImpl();
@@ -381,7 +398,7 @@ public class HibernateNodeTest extends BaseSpringTest
NodeStatus contentNodeStatus2 = new NodeStatusImpl();
contentNodeStatus2.setKey(contentNodeKey2);
contentNodeStatus2.setNode(contentNode2);
contentNodeStatus2.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
contentNodeStatus2.setTransaction(transaction);
getSession().save(contentNodeStatus2);
// create an association to content 1
ChildAssoc assoc1 = new ChildAssocImpl();

View File

@@ -113,6 +113,16 @@
<key-property name="identifier" length="100" />
<key-property name="guid" length="36" />
</composite-id>
<!-- forward assoc to transaction -->
<many-to-one
name="transaction"
class="org.alfresco.repo.domain.hibernate.TransactionImpl"
column="transaction_id"
lazy="proxy"
fetch="select"
unique="false"
not-null="true"
cascade="none" />
<!-- forward assoc to node (optional) -->
<many-to-one
name="node"
@@ -122,7 +132,6 @@
fetch="join"
unique="false"
not-null="false" />
<property name="changeTxnId" column="change_txn_id" type="string" length="56" not-null="true" index="CHANGE_TXN_ID"/>
</class>
<class
@@ -137,33 +146,31 @@
<id name="id" column="id" type="long" >
<generator class="native" />
</id>
<natural-id mutable="true">
<!-- forward assoc to parent node -->
<many-to-one
name="parent"
class="org.alfresco.repo.domain.hibernate.NodeImpl"
lazy="proxy"
fetch="select"
optimistic-lock="true"
not-null="true"
unique-key="UIDX_CHILD_NAME" >
<column name="parent_node_id" />
</many-to-one>
<!-- forward assoc to child node -->
<many-to-one
name="child"
lazy="proxy"
fetch="select"
class="org.alfresco.repo.domain.hibernate.NodeImpl"
optimistic-lock="true"
not-null="true" >
<column name="child_node_id" />
</many-to-one>
<property name="typeQName" column="type_qname" type="QName" length="255" not-null="true" unique-key="UIDX_CHILD_NAME" />
</natural-id>
<!-- forward assoc to parent node -->
<many-to-one
name="parent"
class="org.alfresco.repo.domain.hibernate.NodeImpl"
lazy="proxy"
fetch="select"
optimistic-lock="true"
not-null="true"
unique-key="UIDX_CHILD_NAME" >
<column name="parent_node_id" />
</many-to-one>
<!-- forward assoc to child node -->
<many-to-one
name="child"
lazy="proxy"
fetch="select"
class="org.alfresco.repo.domain.hibernate.NodeImpl"
optimistic-lock="true"
not-null="true" >
<column name="child_node_id" />
</many-to-one>
<property name="typeQName" column="type_qname" type="QName" length="255" not-null="true" unique-key="UIDX_CHILD_NAME" />
<property name="qname" column="qname" type="QName" length="255" not-null="true" />
<property name="childNodeName" column="child_node_name" type="string" length="50" not-null="true" unique-key="UIDX_CHILD_NAME" />
<property name="childNodeNameCrc" column="child_node_name_crc" type="long" not-null="true" unique-key="UIDX_CHILD_NAME" />
<property name="qname" column="qname" type="QName" length="255" not-null="true" />
<property name="isPrimary" column="is_primary" />
<property name="index" column="assoc_index" />
</class>
@@ -309,25 +316,26 @@
<query name="node.GetNextChangeTxnIds">
select distinct
status.changeTxnId
transaction.changeTxnId
from
org.alfresco.repo.domain.hibernate.NodeStatusImpl as status
org.alfresco.repo.domain.hibernate.TransactionImpl as transaction
where
status.changeTxnId > :currentTxnId
transaction.changeTxnId > :currentTxnId
order by
status.changeTxnId
transaction.changeTxnId
</query>
<query name="node.GetChangedNodeStatusesCount">
select
count(status.changeTxnId)
count(transaction.changeTxnId)
from
org.alfresco.repo.domain.hibernate.NodeStatusImpl as status
join status.transaction as transaction
where
status.key.protocol = :storeProtocol and
status.key.identifier = :storeIdentifier and
status.node.id is not null and
status.changeTxnId = :changeTxnId
transaction.changeTxnId = :changeTxnId
</query>
<query name="node.GetChangedNodeStatuses">
@@ -335,11 +343,12 @@
status
from
org.alfresco.repo.domain.hibernate.NodeStatusImpl as status
join status.transaction as transaction
where
status.key.protocol = :storeProtocol and
status.key.identifier = :storeIdentifier and
status.node.id is not null and
status.changeTxnId = :changeTxnId
transaction.changeTxnId = :changeTxnId
</query>
<query name="node.GetDeletedNodeStatuses">
@@ -347,11 +356,12 @@
status
from
org.alfresco.repo.domain.hibernate.NodeStatusImpl as status
join status.transaction as transaction
where
status.key.protocol = :storeProtocol and
status.key.identifier = :storeIdentifier and
status.node.id is null and
status.changeTxnId = :changeTxnId
transaction.changeTxnId = :changeTxnId
</query>
<query name="node.GetContentDataStrings">

View File

@@ -21,6 +21,7 @@ import java.io.Serializable;
import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.NodeKey;
import org.alfresco.repo.domain.NodeStatus;
import org.alfresco.repo.domain.Transaction;
import org.alfresco.util.EqualsHelper;
/**
@@ -34,15 +35,16 @@ public class NodeStatusImpl implements NodeStatus, Serializable
private NodeKey key;
private Node node;
private String changeTxnId;
private Transaction transaction;
@Override
public String toString()
{
StringBuilder sb = new StringBuilder(50);
sb.append("NodeStatus")
.append("[key=").append(key)
.append(", node=").append(node == null ? null : node.getNodeRef())
.append(", txn=").append(changeTxnId)
.append(", txn=").append(transaction)
.append("]");
return sb.toString();
}
@@ -85,14 +87,14 @@ public class NodeStatusImpl implements NodeStatus, Serializable
this.node = node;
}
public String getChangeTxnId()
public Transaction getTransaction()
{
return changeTxnId;
return transaction;
}
public void setChangeTxnId(String txnId)
public void setTransaction(Transaction transaction)
{
this.changeTxnId = txnId;
this.transaction = transaction;
}
public boolean isDeleted()

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.domain.hibernate;
import java.io.Serializable;
import org.alfresco.repo.domain.Server;
/**
* Bean containing all the persistence data representing a <b>Server</b>.
* <p>
* This implementation of the {@link org.alfresco.repo.domain.Service Service} interface is
* Hibernate specific.
*
* @author Derek Hulley
*/
public class ServerImpl extends LifecycleAdapter implements Server, Serializable
{
private static final long serialVersionUID = 8063452519040344479L;
private Long id;
private String ipAddress;
public ServerImpl()
{
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder(50);
sb.append("Server")
.append("[id=").append(id)
.append(", ipAddress=").append(ipAddress)
.append("]");
return sb.toString();
}
public Long getId()
{
return id;
}
/**
* For Hibernate use
*/
@SuppressWarnings("unused")
private void setId(Long id)
{
this.id = id;
}
public String getIpAddress()
{
return ipAddress;
}
public void setIpAddress(String ipAddress)
{
this.ipAddress = ipAddress;
}
}

View File

@@ -0,0 +1,62 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
'-//Hibernate/Hibernate Mapping DTD 3.0//EN'
'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
<hibernate-mapping>
<class
name="org.alfresco.repo.domain.hibernate.TransactionImpl"
proxy="org.alfresco.repo.domain.Transaction"
table="alf_transaction"
dynamic-update="false"
dynamic-insert="false"
select-before-update="false"
lazy="true"
optimistic-lock="version" >
<!-- auto-generated ID -->
<id name="id" column="id" type="long" >
<generator class="native" />
</id>
<!-- forward assoc to server IP -->
<many-to-one
name="server"
class="org.alfresco.repo.domain.hibernate.ServerImpl"
column="server_id"
lazy="proxy"
fetch="select"
unique="false"
not-null="false"
cascade="none" />
<property name="changeTxnId" column="change_txn_id" type="string" length="56" not-null="true" index="CHANGE_TXN_ID"/>
</class>
<class
name="org.alfresco.repo.domain.hibernate.ServerImpl"
proxy="org.alfresco.repo.domain.Server"
table="alf_server"
dynamic-update="false"
dynamic-insert="false"
select-before-update="false"
lazy="true"
optimistic-lock="version" >
<!-- auto-generated ID -->
<id name="id" column="id" type="long" >
<generator class="native" />
</id>
<natural-id>
<property name="ipAddress" column="ip_address" type="string" length="15" not-null="true" />
</natural-id>
</class>
<query name="server.getServerByIpAddress">
select
server
from
org.alfresco.repo.domain.hibernate.ServerImpl as server
where
server.ipAddress = :ipAddress
</query>
</hibernate-mapping>

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.domain.hibernate;
import java.io.Serializable;
import org.alfresco.repo.domain.Server;
import org.alfresco.repo.domain.Transaction;
/**
* Bean containing all the persistence data representing a <b>Transaction</b>.
* <p>
* This implementation of the {@link org.alfresco.repo.domain.Transaction Transaction} interface is
* Hibernate specific.
*
* @author Derek Hulley
*/
public class TransactionImpl extends LifecycleAdapter implements Transaction, Serializable
{
private static final long serialVersionUID = -8264339795578077552L;
private Long id;
private String changeTxnId;
private Server server;
public TransactionImpl()
{
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder(50);
sb.append("Transaction")
.append("[id=").append(id)
.append(", changeTxnId=").append(changeTxnId)
.append("]");
return sb.toString();
}
public Long getId()
{
return id;
}
/**
* For Hibernate use
*/
@SuppressWarnings("unused")
private void setId(Long id)
{
this.id = id;
}
public String getChangeTxnId()
{
return changeTxnId;
}
public void setChangeTxnId(String changeTransactionId)
{
this.changeTxnId = changeTransactionId;
}
public Server getServer()
{
return server;
}
public void setServer(Server server)
{
this.server = server;
}
}

View File

@@ -0,0 +1,529 @@
/*
* Copyright (C) 2006 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.domain.schema;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.Writer;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.Dialect;
import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
import org.springframework.util.ResourceUtils;
/**
* Bootstraps the schema and schema update. The schema is considered missing if the applied patch table
* is not present, and the schema is considered empty if the applied patch table is empty.
*
* @author Derek Hulley
*/
public class SchemaBootstrap implements ApplicationListener
{
/** The placeholder for the configured <code>Dialect</code> class name: <b>${db.script.dialect}</b> */
private static final String PLACEHOLDER_SCRIPT_DIALECT = "\\$\\{db\\.script\\.dialect\\}";
private static final String MSG_EXECUTING_SCRIPT = "schema.update.msg.executing_script";
private static final String ERR_UPDATE_FAILED = "schema.update.err.update_failed";
private static final String ERR_VALIDATION_FAILED = "schema.update.err.validation_failed";
private static final String ERR_SCRIPT_NOT_RUN = "schema.update.err.update_script_not_run";
private static final String ERR_SCRIPT_NOT_FOUND = "schema.update.err.script_not_found";
private static final String ERR_STATEMENT_TERMINATOR = "schema.update.err.statement_terminator";
private static Log logger = LogFactory.getLog(SchemaBootstrap.class);
private LocalSessionFactoryBean localSessionFactory;
private String schemaOuputFilename;
private boolean updateSchema;
private List<String> postCreateScriptUrls;
private List<SchemaUpgradeScriptPatch> validateUpdateScriptPatches;
private List<SchemaUpgradeScriptPatch> applyUpdateScriptPatches;
public SchemaBootstrap()
{
postCreateScriptUrls = new ArrayList<String>(1);
validateUpdateScriptPatches = new ArrayList<SchemaUpgradeScriptPatch>(4);
applyUpdateScriptPatches = new ArrayList<SchemaUpgradeScriptPatch>(4);
}
public void setLocalSessionFactory(LocalSessionFactoryBean localSessionFactory) throws BeansException
{
this.localSessionFactory = localSessionFactory;
}
/**
* Set this to output the full database creation script
*
* @param schemaOuputFilename the name of a file to dump the schema to, or null to ignore
*/
public void setSchemaOuputFilename(String schemaOuputFilename)
{
this.schemaOuputFilename = schemaOuputFilename;
}
/**
* Set whether to modify the schema or not. Either way, the schema will be validated.
*
* @param updateSchema true to update and validate the schema, otherwise false to just
* validate the schema. Default is <b>true</b>.
*/
public void setUpdateSchema(boolean updateSchema)
{
this.updateSchema = updateSchema;
}
/**
* Set the scripts that must be executed after the schema has been created.
*
* @param postCreateScriptUrls file URLs
*
* @see #PLACEHOLDER_SCRIPT_DIALECT
*/
public void setPostCreateScriptUrls(List<String> postUpdateScriptUrls)
{
this.postCreateScriptUrls = postUpdateScriptUrls;
}
/**
* Set the schema script patches that must have been applied. These will not be
* applied to the database. These can be used where the script <u>cannot</u> be
* applied automatically or where a particular upgrade path is no longer supported.
* For example, at version 3.0, the upgrade scripts for version 1.4 may be considered
* unsupported - this doesn't prevent the manual application of the scripts, though.
*
* @param applyUpdateScriptPatches a list of schema patches to check
*/
public void setValidateUpdateScriptPatches(List<SchemaUpgradeScriptPatch> scriptPatches)
{
this.validateUpdateScriptPatches = scriptPatches;
}
/**
* Set the schema script patches that may be executed during an update.
*
* @param applyUpdateScriptPatches a list of schema patches to check
*/
public void setApplyUpdateScriptPatches(List<SchemaUpgradeScriptPatch> scriptPatches)
{
this.applyUpdateScriptPatches = scriptPatches;
}
public void onApplicationEvent(ApplicationEvent event)
{
if (!(event instanceof ContextRefreshedEvent))
{
// only work on startup
return;
}
// do everything in a transaction
Session session = getLocalSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
try
{
// make sure that we don't autocommit
Connection connection = session.connection();
connection.setAutoCommit(false);
Configuration cfg = localSessionFactory.getConfiguration();
// dump the schema, if required
if (schemaOuputFilename != null)
{
File schemaOutputFile = new File(schemaOuputFilename);
dumpSchemaCreate(cfg, schemaOutputFile);
}
// update the schema, if required
if (updateSchema)
{
updateSchema(cfg, session, connection);
}
// verify that all patches have been applied correctly
checkSchemaPatchScripts(cfg, session, connection, validateUpdateScriptPatches, false); // check scripts
checkSchemaPatchScripts(cfg, session, connection, applyUpdateScriptPatches, false); // check scripts
// all done successfully
transaction.commit();
}
catch (Throwable e)
{
try { transaction.rollback(); } catch (Throwable ee) {}
if (updateSchema)
{
throw new AlfrescoRuntimeException(ERR_UPDATE_FAILED, e);
}
else
{
throw new AlfrescoRuntimeException(ERR_VALIDATION_FAILED, e);
}
}
}
private void dumpSchemaCreate(Configuration cfg, File schemaOutputFile)
{
// if the file exists, delete it
if (schemaOutputFile.exists())
{
schemaOutputFile.delete();
}
SchemaExport schemaExport = new SchemaExport(cfg)
.setFormat(true)
.setHaltOnError(true)
.setOutputFile(schemaOutputFile.getAbsolutePath())
.setDelimiter(";");
schemaExport.execute(false, false, false, true);
}
private SessionFactory getLocalSessionFactory()
{
return (SessionFactory) localSessionFactory.getObject();
}
/**
* @return Returns the number of applied patches
*/
private int countAppliedPatches(Connection connection) throws Exception
{
Statement stmt = connection.createStatement();
try
{
ResultSet rs = stmt.executeQuery("select count(id) from alf_applied_patch");
rs.next();
int count = rs.getInt(1);
return count;
}
catch (Throwable e)
{
// we'll try another table name
}
finally
{
try { stmt.close(); } catch (Throwable e) {}
}
// for pre-1.4 databases, the table was named differently
stmt = connection.createStatement();
try
{
ResultSet rs = stmt.executeQuery("select count(id) from applied_patch");
rs.next();
int count = rs.getInt(1);
return count;
}
finally
{
try { stmt.close(); } catch (Throwable e) {}
}
}
/**
* @return Returns the number of applied patches
*/
private boolean didPatchSucceed(Connection connection, String patchId) throws Exception
{
Statement stmt = connection.createStatement();
try
{
ResultSet rs = stmt.executeQuery("select succeeded from alf_applied_patch where id = '" + patchId + "'");
if (!rs.next())
{
return false;
}
boolean succeeded = rs.getBoolean(1);
return succeeded;
}
catch (Throwable e)
{
// we'll try another table name
}
finally
{
try { stmt.close(); } catch (Throwable e) {}
}
// for pre-1.4 databases, the table was named differently
stmt = connection.createStatement();
try
{
ResultSet rs = stmt.executeQuery("select succeeded from applied_patch where id = '" + patchId + "'");
if (!rs.next())
{
return false;
}
boolean succeeded = rs.getBoolean(1);
return succeeded;
}
finally
{
try { stmt.close(); } catch (Throwable e) {}
}
}
/**
* Builds the schema from scratch or applies the necessary patches to the schema.
*/
private void updateSchema(Configuration cfg, Session session, Connection connection) throws Exception
{
boolean create = false;
try
{
countAppliedPatches(connection);
}
catch (Throwable e)
{
create = true;
}
if (create)
{
// the applied patch table is missing - we assume that all other tables are missing
// perform a full update using Hibernate-generated statements
File tempFile = TempFileProvider.createTempFile("AlfrescoSchemaCreate", ".sql");
dumpSchemaCreate(cfg, tempFile);
executeScriptFile(cfg, connection, tempFile);
// execute post-create scripts (not patches)
for (String scriptUrl : this.postCreateScriptUrls)
{
executeScriptUrl(cfg, connection, scriptUrl);
}
}
else
{
// we have a database, so just run the update scripts
checkSchemaPatchScripts(cfg, session, connection, validateUpdateScriptPatches, false); // check for scripts that must have been run
checkSchemaPatchScripts(cfg, session, connection, applyUpdateScriptPatches, true); // execute scripts as required
// let Hibernate do any required updates
File tempFile = null;
Writer writer = null;
try
{
final Dialect dialect = Dialect.getDialect(cfg.getProperties());
DatabaseMetadata metadata = new DatabaseMetadata(connection, dialect);
String[] sqls = cfg.generateSchemaUpdateScript(dialect, metadata);
if (sqls.length > 0)
{
tempFile = TempFileProvider.createTempFile("AlfrescoSchemaUpdate", ".sql");
writer = new BufferedWriter(new FileWriter(tempFile));
for (String sql : sqls)
{
writer.append(sql);
writer.append(";\n");
}
}
}
finally
{
if (writer != null)
{
try {writer.close();} catch (Throwable e) {}
}
}
// execute if there were changes raised by Hibernate
if (tempFile != null)
{
executeScriptFile(cfg, connection, tempFile);
}
}
}
/**
* Check that the necessary scripts have been executed against the database
*/
private void checkSchemaPatchScripts(
Configuration cfg,
Session session,
Connection connection,
List<SchemaUpgradeScriptPatch> scriptPatches,
boolean apply) throws Exception
{
// first check if there have been any applied patches
int appliedPatchCount = countAppliedPatches(connection);
if (appliedPatchCount == 0)
{
// This is a new schema, so upgrade scripts are irrelevant
// and patches will not have been applied yet
return;
}
for (SchemaUpgradeScriptPatch patch : scriptPatches)
{
final String patchId = patch.getId();
final String scriptUrl = patch.getScriptUrl();
// check if the script was successfully executed
boolean wasSuccessfullyApplied = didPatchSucceed(connection, patchId);
if (wasSuccessfullyApplied)
{
// nothing to do - it has been done before
continue;
}
else if (!apply)
{
// the script was not run and may not be run automatically
throw AlfrescoRuntimeException.create(ERR_SCRIPT_NOT_RUN, scriptUrl);
}
// it wasn't run and it can be run now
executeScriptUrl(cfg, connection, scriptUrl);
}
}
private void executeScriptUrl(Configuration cfg, Connection connection, String scriptUrl) throws Exception
{
Dialect dialect = Dialect.getDialect(cfg.getProperties());
File scriptFile = getScriptFile(dialect.getClass(), scriptUrl);
// check that it exists
if (scriptFile == null)
{
throw AlfrescoRuntimeException.create(ERR_SCRIPT_NOT_FOUND, scriptUrl);
}
// now execute it
executeScriptFile(cfg, connection, scriptFile);
}
/**
* Replaces the dialect placeholder in the script URL and attempts to find a file for
* it. If not found, the dialect hierarchy will be walked until a compatible script is
* found. This makes it possible to have scripts that are generic to all dialects.
*
* @return Returns the file if found, otherwise null
*/
private File getScriptFile(Class dialectClazz, String scriptUrl) throws Exception
{
// replace the dialect placeholder
String dialectScriptUrl = scriptUrl.replaceAll(PLACEHOLDER_SCRIPT_DIALECT, dialectClazz.getName());
// get a handle on the resource
try
{
File scriptFile = ResourceUtils.getFile(dialectScriptUrl);
if (scriptFile.exists())
{
// found a compatible dialect version
return scriptFile;
}
}
catch (FileNotFoundException e)
{
// doesn't exist
}
// it wasn't found. Get the superclass of the dialect and try again
Class superClazz = dialectClazz.getSuperclass();
if (Dialect.class.isAssignableFrom(superClazz))
{
// we still have a Dialect - try again
return getScriptFile(superClazz, scriptUrl);
}
else
{
// we have exhausted all options
return null;
}
}
private void executeScriptFile(Configuration cfg, Connection connection, File scriptFile) throws Exception
{
logger.info(I18NUtil.getMessage(MSG_EXECUTING_SCRIPT, scriptFile));
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(scriptFile), "UTF8"));
try
{
int line = 0;
// loop through all statements
StringBuilder sb = new StringBuilder(1024);
while(true)
{
String sql = reader.readLine();
line++;
if (sql == null)
{
// nothing left in the file
break;
}
// trim it
sql = sql.trim();
if (sql.length() == 0 ||
sql.startsWith( "--" ) ||
sql.startsWith( "//" ) ||
sql.startsWith( "/*" ) )
{
if (sb.length() > 0)
{
// we have an unterminated statement
throw AlfrescoRuntimeException.create(ERR_STATEMENT_TERMINATOR, (line - 1), scriptFile);
}
// there has not been anything to execute - it's just a comment line
continue;
}
// have we reached the end of a statement?
boolean execute = false;
if (sql.endsWith(";"))
{
sql = sql.substring(0, sql.length() - 1);
execute = true;
}
// append to the statement being built up
sb.append(" ").append(sql);
// execute, if required
if (execute)
{
Statement stmt = connection.createStatement();
try
{
sql = sb.toString();
if (logger.isDebugEnabled())
{
logger.debug("Executing statment: " + sql);
}
stmt.execute(sql);
sb = new StringBuilder(1024);
}
finally
{
try { stmt.close(); } catch (Throwable e) {}
}
}
}
}
finally
{
try { reader.close(); } catch (Throwable e) {}
}
}
}

View File

@@ -586,13 +586,20 @@ public class FileFolderServiceImpl implements FileFolderService
}
else
{
// copy the node
targetNodeRef = copyService.copy(
sourceNodeRef,
targetParentRef,
assocRef.getTypeQName(),
qname,
true);
try
{
// copy the node
targetNodeRef = copyService.copy(
sourceNodeRef,
targetParentRef,
assocRef.getTypeQName(),
qname,
true);
}
catch (DuplicateChildNodeNameException e)
{
throw new FileExistsException(targetParentRef, newName);
}
}
// Only update the name if it has changed

View File

@@ -336,6 +336,10 @@ public class FileFolderServiceImplTest extends TestCase
// make sure that it is an immediate child of the root
List<FileInfo> checkFileInfos = fileFolderService.search(workingRootNodeRef, NAME_L1_FOLDER_A, false);
assertEquals("Folder not copied to root", 1, checkFileInfos.size());
// copy properly
FileInfo checkFileInfo = fileFolderService.copy(folderToCopyRef, null, "new name");
checkFileInfos = fileFolderService.search(workingRootNodeRef, checkFileInfo.getName(), false);
assertEquals("Folder not renamed in root", 1, checkFileInfos.size());
// attempt illegal copy (existing)
try
{
@@ -346,10 +350,6 @@ public class FileFolderServiceImplTest extends TestCase
{
// expected
}
// copy properly
FileInfo checkFileInfo = fileFolderService.copy(folderToCopyRef, null, "new name");
checkFileInfos = fileFolderService.search(workingRootNodeRef, checkFileInfo.getName(), false);
assertEquals("Folder not renamed in root", 1, checkFileInfos.size());
}
public void testCreateFolder() throws Exception

View File

@@ -1630,10 +1630,7 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
NodeRef defRef = pathDefRef.getChildRef();
// now browse down using the node service
NodeRef checkParentRef = nodeService.getChildByName(rootNodeRef, ASSOC_TYPE_QNAME_TEST_CHILDREN, parentRef.getId());
assertNotNull("First level, non-named node not found", checkParentRef);
assertEquals(parentRef, checkParentRef);
NodeRef checkAbcRef = nodeService.getChildByName(checkParentRef, ASSOC_TYPE_QNAME_TEST_CONTAINS, "abc");
NodeRef checkAbcRef = nodeService.getChildByName(parentRef, ASSOC_TYPE_QNAME_TEST_CONTAINS, "abc");
assertNotNull("Second level, named node 'ABC' not found", checkAbcRef);
assertEquals(abcRef, checkAbcRef);
NodeRef checkDefRef = nodeService.getChildByName(checkAbcRef, ASSOC_TYPE_QNAME_TEST_CONTAINS, "def");

View File

@@ -149,7 +149,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
else
{
return new NodeRef.Status(
nodeStatus.getChangeTxnId(),
nodeStatus.getTransaction().getChangeTxnId(),
nodeStatus.isDeleted());
}
}
@@ -1440,11 +1440,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// update old status
NodeStatus oldNodeStatus = nodeDaoService.getNodeStatus(oldNodeRef, true);
oldNodeStatus.setNode(null);
oldNodeStatus.setChangeTxnId(txnId);
oldNodeStatus.getTransaction().setChangeTxnId(txnId);
// create the new status
NodeStatus newNodeStatus = nodeDaoService.getNodeStatus(newNodeRef, true);
newNodeStatus.setNode(nodeToMove);
newNodeStatus.setChangeTxnId(txnId);
newNodeStatus.getTransaction().setChangeTxnId(txnId);
}
}

View File

@@ -16,9 +16,14 @@
*/
package org.alfresco.repo.node.db.hibernate;
import java.io.Serializable;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import java.util.zip.CRC32;
import org.alfresco.error.AlfrescoRuntimeException;
@@ -28,13 +33,17 @@ import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.NodeAssoc;
import org.alfresco.repo.domain.NodeKey;
import org.alfresco.repo.domain.NodeStatus;
import org.alfresco.repo.domain.Server;
import org.alfresco.repo.domain.Store;
import org.alfresco.repo.domain.StoreKey;
import org.alfresco.repo.domain.Transaction;
import org.alfresco.repo.domain.hibernate.ChildAssocImpl;
import org.alfresco.repo.domain.hibernate.NodeAssocImpl;
import org.alfresco.repo.domain.hibernate.NodeImpl;
import org.alfresco.repo.domain.hibernate.NodeStatusImpl;
import org.alfresco.repo.domain.hibernate.ServerImpl;
import org.alfresco.repo.domain.hibernate.StoreImpl;
import org.alfresco.repo.domain.hibernate.TransactionImpl;
import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionalDao;
@@ -71,9 +80,14 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
private static final String QUERY_GET_TARGET_ASSOCS = "node.GetTargetAssocs";
private static final String QUERY_GET_SOURCE_ASSOCS = "node.GetSourceAssocs";
private static final String QUERY_GET_CONTENT_DATA_STRINGS = "node.GetContentDataStrings";
private static final String QUERY_GET_SERVER_BY_IPADDRESS = "server.getServerByIpAddress";
/** a uuid identifying this unique instance */
private String uuid;
private final String uuid;
private final ReadLock serverReadLock;
private final WriteLock serverWriteLock;
private Server server;
/**
*
@@ -81,6 +95,10 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
public HibernateNodeDaoServiceImpl()
{
this.uuid = GUID.generate();
ReentrantReadWriteLock serverReadWriteLock = new ReentrantReadWriteLock();
serverReadLock = serverReadWriteLock.readLock();
serverWriteLock = serverReadWriteLock.writeLock();
}
/**
@@ -108,6 +126,93 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
return uuid.hashCode();
}
/**
* Gets/creates the <b>server</b> instance to use for the life of this instance
*/
private Server getServer()
{
// get readlock
serverReadLock.lock();
try
{
if (server != null)
{
return server;
}
}
finally
{
serverReadLock.unlock();
}
// get the write lock
serverWriteLock.lock();
try
{
final String ipAddress = InetAddress.getLocalHost().getHostAddress();
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
Query query = session
.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_SERVER_BY_IPADDRESS)
.setString("ipAddress", ipAddress);
return query.uniqueResult();
}
};
server = (Server) getHibernateTemplate().execute(callback);
// create it if it doesn't exist
if (server == null)
{
server = new ServerImpl();
server.setIpAddress(ipAddress);
try
{
getSession().save(server);
}
catch (DataIntegrityViolationException e)
{
// get it again
server = (Server) getHibernateTemplate().execute(callback);
if (server == null)
{
throw new AlfrescoRuntimeException("Unable to create server instance: " + ipAddress);
}
}
}
return server;
}
catch (Exception e)
{
throw new AlfrescoRuntimeException("Failed to create server instance", e);
}
finally
{
serverWriteLock.unlock();
}
}
private static final String RESOURCE_KEY_TRANSACTION_ID = "hibernate.transaction.id";
private Transaction getCurrentTransaction()
{
Transaction transaction = null;
Serializable txnId = (Serializable) AlfrescoTransactionSupport.getResource(RESOURCE_KEY_TRANSACTION_ID);
if (txnId == null)
{
// no transaction instance has been bound to the transaction
transaction = new TransactionImpl();
transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
transaction.setServer(getServer());
txnId = getHibernateTemplate().save(transaction);
// bind the id
AlfrescoTransactionSupport.bindResource(RESOURCE_KEY_TRANSACTION_ID, txnId);
}
else
{
transaction = (Transaction) getHibernateTemplate().get(TransactionImpl.class, txnId);
}
return transaction;
}
/**
* Does this <tt>Session</tt> contain any changes which must be
* synchronized with the store?
@@ -218,7 +323,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
{
status = new NodeStatusImpl();
status.setKey(nodeKey);
status.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
status.setTransaction(getCurrentTransaction());
getHibernateTemplate().save(status);
}
// done
@@ -237,7 +342,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
}
else
{
status.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
status.getTransaction().setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
}
}
@@ -259,13 +364,13 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
// If that is the case, then the session has to be flushed so that the database
// constraints aren't violated as the node creation will write to the database to
// get an ID
if (status.getChangeTxnId().equals(AlfrescoTransactionSupport.getTransactionId()))
if (status.getTransaction().getChangeTxnId().equals(AlfrescoTransactionSupport.getTransactionId()))
{
// flush
getHibernateTemplate().flush();
}
}
// build a concrete node based on a bootstrap type
Node node = new NodeImpl();
// set other required properties
@@ -277,7 +382,11 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
// set required status properties
status.setNode(node);
status.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
// assign a transaction
if (status.getTransaction() == null)
{
status.setTransaction(getCurrentTransaction());
}
// persist the nodestatus
getHibernateTemplate().save(status);
@@ -331,7 +440,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
NodeRef nodeRef = node.getNodeRef();
NodeStatus nodeStatus = getNodeStatus(nodeRef, true);
nodeStatus.setNode(null);
nodeStatus.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
nodeStatus.getTransaction().setChangeTxnId(AlfrescoTransactionSupport.getTransactionId());
// finally delete the node
getHibernateTemplate().delete(node);
// flush to ensure constraints can't be violated
@@ -371,7 +480,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
{
/*
* This initial child association creation will fail IFF there is already
* an association of the given type between the two nodes. For new association
* an association of the given type and name between the two nodes. For new association
* creation, this can only occur if two transactions attempt to create a secondary
* child association between the same two nodes. As this is unlikely, it is
* appropriate to just throw a runtime exception and let the second transaction
@@ -383,28 +492,18 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
* if the association is recreated subsequently.
*/
String uuid = childNode.getUuid();
// assign a random name to the node
String randomName = GUID.generate();
ChildAssoc assoc = new ChildAssocImpl();
assoc.setTypeQName(assocTypeQName);
assoc.setChildNodeName(getShortName(uuid));
assoc.setChildNodeNameCrc(getCrc(uuid));
assoc.setChildNodeName(randomName);
assoc.setChildNodeNameCrc(-1L); // random names compete only with each other
assoc.setQname(qname);
assoc.setIsPrimary(isPrimary);
assoc.buildAssociation(parentNode, childNode);
// persist it, catching the duplicate child name
try
{
getHibernateTemplate().save(assoc);
}
catch (DataIntegrityViolationException e)
{
throw new AlfrescoRuntimeException("An association already exists between the two nodes: \n" +
" parent: " + parentNode.getId() + "\n" +
" child: " + childNode.getId() + "\n" +
" assoc: " + assocTypeQName,
e);
}
getHibernateTemplate().save(assoc);
// done
return assoc;
}
@@ -422,17 +521,22 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements
*/
String childNameNew = null;
long crc = -1;
if (childName == null)
{
childNameNew = childAssoc.getChild().getUuid();
// random names compete only with each other, i.e. not at all
childNameNew = GUID.generate();
crc = -1;
}
else
{
// assigned names compete exactly
childNameNew = childName.toLowerCase();
crc = getCrc(childNameNew);
}
final String childNameNewShort = getShortName(childNameNew);
final long childNameNewCrc = getCrc(childNameNew);
final long childNameNewCrc = crc;
// check if the name has changed
if (childAssoc.getChildNodeNameCrc() == childNameNewCrc)

View File

@@ -62,13 +62,13 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
* database is static then the L2 cache usage can be set to use
* the <code>NORMAL</code> mode. <code>REFRESH</code> should be
* used where the server will still be accessed from some clients
* despite the database changing.
* despite the database changing. <code>NORMAL</code> can be used
* in the case of the caches being clustered, i.e. the caches will
* not be out of date w.r.t. the database.
* </li>
* <li>
* This process should not run continuously on a live
* server as it would be performing unecessary work.
* If it was left running, however, it would not
* lead to data corruption or such-like. Use the
* This process should only be used continuously where the index
* transactions are following the database transactions. Use the
* {@link #setRunContinuously(boolean) runContinuously} property
* to change this behaviour.
* </li>
@@ -91,7 +91,7 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
private static boolean started = false;
/** The current transaction ID being processed */
private static String currentTxnId = START_TXN_ID;
/** kept to notify the thread that it should quite */
/** kept to notify the thread that it should quit */
private boolean killThread = false;
/** provides transactions to atomically index each missed transaction */
@@ -104,8 +104,6 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
private SearchService searcher;
/** the component giving direct access to <b>node</b> instances */
private NodeService nodeService;
/** the stores to reindex */
private List<StoreRef> storeRefs;
/** set this to run the index recovery component */
private boolean executeFullRecovery;
/** set this on to keep checking for new transactions and never stop */
@@ -125,8 +123,6 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
public FullIndexRecoveryComponent()
{
this.storeRefs = new ArrayList<StoreRef>(2);
this.killThread = false;
this.executeFullRecovery = false;
this.runContinuously = false;
@@ -193,21 +189,6 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
this.nodeService = nodeService;
}
/**
* Set the stores that need reindexing
*
* @param storeRefStrings a list of strings representing store references
*/
public void setStores(List<String> storeRefStrings)
{
storeRefs.clear();
for (String storeRefStr : storeRefStrings)
{
StoreRef storeRef = new StoreRef(storeRefStr);
storeRefs.add(storeRef);
}
}
/**
* Set this to <code>true</code> to initiate the full index recovery.
* <p>
@@ -299,6 +280,7 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
{
public Object doWork()
{
List<StoreRef> storeRefs = nodeService.getStores();
// reindex each store
for (StoreRef storeRef : storeRefs)
{
@@ -352,8 +334,7 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
if (logger.isDebugEnabled())
{
logger.debug("Full index recovery thread started: \n" +
" continuous: " + runContinuously + "\n" +
" stores: " + storeRefs);
" continuous: " + runContinuously);
}
}
}
@@ -377,8 +358,8 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
// reindex nodes
List<String> txnsIndexed = FullIndexRecoveryComponent.this.reindexNodes();
// reindex missing content
@SuppressWarnings("unused")
int missingContentCount = FullIndexRecoveryComponent.this.reindexMissingContent();
// @SuppressWarnings("unused")
// int missingContentCount = FullIndexRecoveryComponent.this.reindexMissingContent();
// check if the process should terminate
if (txnsIndexed.size() == 0 && !runContinuously)
{
@@ -417,73 +398,6 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
}
}
/**
* @return Returns the number of documents reindexed
*/
private int reindexMissingContent()
{
int count = 0;
for (StoreRef storeRef : storeRefs)
{
count += reindexMissingContent(storeRef);
}
return count;
}
/**
* @param storeRef the store to check for missing content
* @return Returns the number of documents reindexed
*/
private int reindexMissingContent(StoreRef storeRef)
{
SearchParameters sp = new SearchParameters();
sp.addStore(storeRef);
// search for it in the index
String query = "TEXT:" + LuceneIndexerImpl.NOT_INDEXED_CONTENT_MISSING;
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery(query);
ResultSet results = null;
try
{
results = searcher.query(sp);
int count = 0;
// loop over the results and get the details of the nodes that have missing content
List<ChildAssociationRef> assocRefs = results.getChildAssocRefs();
for (ChildAssociationRef assocRef : assocRefs)
{
final NodeRef childNodeRef = assocRef.getChildRef();
// prompt for a reindex - it might fail again, but we just keep plugging away
TransactionWork<Object> reindexWork = new TransactionWork<Object>()
{
public Object doWork()
{
indexer.updateNode(childNodeRef);
return null;
}
};
TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork);
count++;
}
// done
if (logger.isDebugEnabled())
{
logger.debug("Reindexed missing content: \n" +
" store: " + storeRef + "\n" +
" node count: " + count);
}
return count;
}
finally
{
if (results != null)
{
results.close();
}
}
}
/**
* @return Returns the transaction ID just reindexed, i.e. where some work was performed
*/
@@ -572,16 +486,16 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
getSession().setCacheMode(l2CacheMode);
// reindex each store
for (StoreRef storeRef : storeRefs)
{
if (!nodeService.exists(storeRef))
{
// the store is not present
continue;
}
// reindex for store
reindexNodes(storeRef, changeTxnId);
}
// for (StoreRef storeRef : storeRefs)
// {
// if (!nodeService.exists(storeRef))
// {
// // the store is not present
// continue;
// }
// // reindex for store
// reindexNodes(storeRef, changeTxnId);
// }
// done
return null;
}
@@ -675,10 +589,10 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
};
/**
* Retrieve all transaction IDs that are greater than the given transaction ID.
* Retrieve next 50 transaction IDs that are greater than the given transaction ID.
*
* @param currentTxnId the transaction ID that must be less than all returned results
* @return Returns an ordered list of transaction IDs
* @return Returns an ordered list of the next 50 transaction IDs
*/
@SuppressWarnings("unchecked")
public List<String> getNextChangeTxnIds(final String currentTxnId)
@@ -689,6 +603,7 @@ public class FullIndexRecoveryComponent extends HibernateDaoSupport implements I
{
Query query = session.getNamedQuery(QUERY_GET_NEXT_CHANGE_TXN_IDS);
query.setString("currentTxnId", currentTxnId)
.setMaxResults(50)
.setReadOnly(true);
return query.list();
}

View File

@@ -123,7 +123,7 @@ public class FullIndexRecoveryComponentTest extends TestCase
String txnId = TransactionUtil.executeInNonPropagatingUserTransaction(txnService, dropNodeIndexWork);
indexRecoverer.setExecuteFullRecovery(true);
indexRecoverer.setStores(storeRefStrings);
// indexRecoverer.setStores(storeRefStrings);
// reindex
indexRecoverer.reindex();

View File

@@ -0,0 +1,741 @@
///*
// * Copyright (C) 2005-2006 Alfresco, Inc.
// *
// * Licensed under the Mozilla Public License version 1.1
// * with a permitted attribution clause. You may obtain a
// * copy of the License at
// *
// * http://www.alfresco.org/legal/license.txt
// *
// * Unless required by applicable law or agreed to in writing,
// * software distributed under the License is distributed on an
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// * either express or implied. See the License for the specific
// * language governing permissions and limitations under the
// * License.
// */
//package org.alfresco.repo.node.index;
//
//import java.util.ArrayList;
//import java.util.List;
//
//import org.alfresco.error.AlfrescoRuntimeException;
//import org.alfresco.model.ContentModel;
//import org.alfresco.repo.domain.NodeStatus;
//import org.alfresco.repo.search.Indexer;
//import org.alfresco.repo.search.impl.lucene.LuceneIndexerImpl;
//import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer;
//import org.alfresco.repo.transaction.TransactionUtil;
//import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
//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.repository.StoreRef;
//import org.alfresco.service.cmr.search.ResultSet;
//import org.alfresco.service.cmr.search.SearchParameters;
//import org.alfresco.service.cmr.search.SearchService;
//import org.alfresco.service.transaction.TransactionService;
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
//import org.hibernate.CacheMode;
//import org.hibernate.Query;
//import org.hibernate.Session;
//import org.springframework.orm.hibernate3.HibernateCallback;
//import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
//
///**
// * Ensures that the FTS indexing picks up on any outstanding documents that
// * require indexing.
// * <p>
// * This component must be used as a singleton (one per VM) and may only be
// * called to reindex once. It will start a thread that processes all available
// * transactions and keeps checking to ensure that the index is up to date with
// * the latest database changes.
// * <p>
// * <b>The following points are important:</b>
// * <ul>
// * <li>
// * By default, the Hibernate L2 cache is used during processing.
// * This can be disabled by either disabling the L2 cache globally
// * for the server (not recommended) or by setting the
// * {@link #setL2CacheMode(String) l2CacheMode} property. If the
// * database is static then the L2 cache usage can be set to use
// * the <code>NORMAL</code> mode. <code>REFRESH</code> should be
// * used where the server will still be accessed from some clients
// * despite the database changing. <code>NORMAL</code> can be used
// * in the case of the caches being clustered, i.e. the caches will
// * not be out of date w.r.t. the database.
// * </li>
// * <li>
// * This process should only be used continuously where the index
// * transactions are following the database transactions. Use the
// * {@link #setRunContinuously(boolean) runContinuously} property
// * to change this behaviour.
// * </li>
// * </ul>
// *
// * @author Derek Hulley
// */
//public class MissingContentReindexComponent extends HibernateDaoSupport implements IndexRecovery
//{
// public static final String QUERY_GET_NEXT_CHANGE_TXN_IDS = "node.GetNextChangeTxnIds";
// public static final String QUERY_GET_CHANGED_NODE_STATUSES = "node.GetChangedNodeStatuses";
// public static final String QUERY_GET_DELETED_NODE_STATUSES = "node.GetDeletedNodeStatuses";
// public static final String QUERY_GET_CHANGED_NODE_STATUSES_COUNT = "node.GetChangedNodeStatusesCount";
//
// private static final String START_TXN_ID = "000";
//
// private static Log logger = LogFactory.getLog(FullIndexRecoveryComponent.class);
//
// /** ensures that this process is kicked off once per VM */
// private static boolean started = false;
// /** The current transaction ID being processed */
// private static String currentTxnId = START_TXN_ID;
// /** kept to notify the thread that it should quite */
// private boolean killThread = false;
//
// /** provides transactions to atomically index each missed transaction */
// private TransactionService transactionService;
// /** the component to index the node hierarchy */
// private Indexer indexer;
// /** the FTS indexer that we will prompt to pick up on any un-indexed text */
// private FullTextSearchIndexer ftsIndexer;
// /** the component providing searches of the indexed nodes */
// private SearchService searcher;
// /** the component giving direct access to <b>node</b> instances */
// private NodeService nodeService;
// /** set this to run the index recovery component */
// private boolean executeFullRecovery;
// /** set this on to keep checking for new transactions and never stop */
// private boolean runContinuously;
// /** set the time to wait between checking indexes */
// private long waitTime;
// /** controls how the L2 cache is used */
// private CacheMode l2CacheMode;
//
// /**
// * @return Returns the ID of the current (or last) transaction processed
// */
// public static String getCurrentTransactionId()
// {
// return currentTxnId;
// }
//
// public FullIndexRecoveryComponent()
// {
// this.killThread = false;
// this.executeFullRecovery = false;
// this.runContinuously = false;
// this.waitTime = 1000L;
// this.l2CacheMode = CacheMode.REFRESH;
//
// // ensure that we kill the thread when the VM is shutting down
// Runnable shutdownRunnable = new Runnable()
// {
// public void run()
// {
// killThread = true;
// };
// };
// Thread shutdownThread = new Thread(shutdownRunnable);
// Runtime.getRuntime().addShutdownHook(shutdownThread);
// }
//
// /**
// * @return Returns true if the component has already been started
// */
// public static boolean isStarted()
// {
// return started;
// }
//
// /**
// * @param transactionService provide transactions to index each missed transaction
// */
// public void setTransactionService(TransactionService transactionService)
// {
// this.transactionService = transactionService;
// }
//
// /**
// * @param indexer the indexer that will be index
// */
// public void setIndexer(Indexer indexer)
// {
// this.indexer = indexer;
// }
//
// /**
// * @param ftsIndexer the FTS background indexer
// */
// public void setFtsIndexer(FullTextSearchIndexer ftsIndexer)
// {
// this.ftsIndexer = ftsIndexer;
// }
//
// /**
// * @param searcher component providing index searches
// */
// public void setSearcher(SearchService searcher)
// {
// this.searcher = searcher;
// }
//
// /**
// * @param nodeService provides information about nodes for indexing
// */
// public void setNodeService(NodeService nodeService)
// {
// this.nodeService = nodeService;
// }
//
// /**
// * Set this to <code>true</code> to initiate the full index recovery.
// * <p>
// * This used to default to <code>true</code> but is now false. Set this
// * if the potentially long-running process of checking and fixing the
// * indexes must be started.
// *
// * @param executeFullRecovery
// */
// public void setExecuteFullRecovery(boolean executeFullRecovery)
// {
// this.executeFullRecovery = executeFullRecovery;
// }
//
// /**
// * Set this to ensure that the process continuously checks for new transactions.
// * If not, it will permanently terminate once it catches up with the current
// * transactions.
// *
// * @param runContinuously true to never cease looking for new transactions
// */
// public void setRunContinuously(boolean runContinuously)
// {
// this.runContinuously = runContinuously;
// }
//
// /**
// * Set the time to wait between checking for new transaction changes in the database.
// *
// * @param waitTime the time to wait in milliseconds
// */
// public void setWaitTime(long waitTime)
// {
// this.waitTime = waitTime;
// }
//
// /**
// * Set the hibernate cache mode by name
// *
// * @see org.hibernate.CacheMode
// */
// public void setL2CacheMode(String l2CacheModeStr)
// {
// if (l2CacheModeStr.equals("GET"))
// {
// l2CacheMode = CacheMode.GET;
// }
// else if (l2CacheModeStr.equals("IGNORE"))
// {
// l2CacheMode = CacheMode.IGNORE;
// }
// else if (l2CacheModeStr.equals("NORMAL"))
// {
// l2CacheMode = CacheMode.NORMAL;
// }
// else if (l2CacheModeStr.equals("PUT"))
// {
// l2CacheMode = CacheMode.PUT;
// }
// else if (l2CacheModeStr.equals("REFRESH"))
// {
// l2CacheMode = CacheMode.REFRESH;
// }
// else
// {
// throw new IllegalArgumentException("Unrecognised Hibernate L2 cache mode: " + l2CacheModeStr);
// }
// }
//
// /**
// * Ensure that the index is up to date with the current state of the persistence layer.
// * The full list of unique transaction change IDs is retrieved and used to detect
// * which are not present in the index. All the node changes and deletions for the
// * remaining transactions are then indexed.
// */
// public synchronized void reindex()
// {
// if (FullIndexRecoveryComponent.started)
// {
// throw new AlfrescoRuntimeException
// ("Only one FullIndexRecoveryComponent may be used per VM and it may only be called once");
// }
//
// // ensure that we don't redo this work
// FullIndexRecoveryComponent.started = true;
//
// // work to mark the stores for full text reindexing
// TransactionWork<Object> ftsReindexWork = new TransactionWork<Object>()
// {
// public Object doWork()
// {
// List<StoreRef> storeRefs = nodeService.getStores();
// // reindex each store
// for (StoreRef storeRef : storeRefs)
// {
// // check if the store exists
// if (!nodeService.exists(storeRef))
// {
// // store does not exist
// if (logger.isDebugEnabled())
// {
// logger.debug("Skipping reindex of non-existent store: " + storeRef);
// }
// continue;
// }
//
// // prompt FTS to reindex the store
// ftsIndexer.requiresIndex(storeRef);
// }
// // done
// if (logger.isDebugEnabled())
// {
// logger.debug("Prompted FTS index on stores: " + storeRefs);
// }
// return null;
// }
// };
// TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, ftsReindexWork);
//
// // start full index recovery, if necessary
// if (!this.executeFullRecovery)
// {
// if (logger.isDebugEnabled())
// {
// logger.debug("Full index recovery is off - quitting");
// }
// }
// else
// {
// // set the state of the reindex
// FullIndexRecoveryComponent.currentTxnId = START_TXN_ID;
//
// // start a stateful thread that will begin processing the reindexing the transactions
// Runnable runnable = new ReindexRunner();
// Thread reindexThread = new Thread(runnable);
// // make it a daemon thread
// reindexThread.setDaemon(true);
// // it should not be a high priority
// reindexThread.setPriority(Thread.MIN_PRIORITY);
// // start it
// reindexThread.start();
//
// if (logger.isDebugEnabled())
// {
// logger.debug("Full index recovery thread started: \n" +
// " continuous: " + runContinuously);
// }
// }
// }
//
// /**
// * Stateful thread runnable that executes reindex calls.
// *
// * @see FullIndexRecoveryComponent#reindexNodes()
// *
// * @author Derek Hulley
// */
// private class ReindexRunner implements Runnable
// {
// public void run()
// {
// // keep this thread going permanently
// while (!killThread)
// {
// try
// {
// // reindex nodes
// List<String> txnsIndexed = FullIndexRecoveryComponent.this.reindexNodes();
// // reindex missing content
// @SuppressWarnings("unused")
// int missingContentCount = FullIndexRecoveryComponent.this.reindexMissingContent();
// // check if the process should terminate
// if (txnsIndexed.size() == 0 && !runContinuously)
// {
// // the thread has caught up with all the available work and should not
// // run continuously
// if (logger.isDebugEnabled())
// {
// logger.debug("Thread quitting - no more available indexing to do: \n" +
// " last txn: " + FullIndexRecoveryComponent.getCurrentTransactionId());
// }
// break;
// }
// // brief pause
// synchronized(FullIndexRecoveryComponent.this)
// {
// FullIndexRecoveryComponent.this.wait(waitTime);
// }
// }
// catch (InterruptedException e)
// {
// // ignore
// }
// catch (Throwable e)
// {
// if (killThread)
// {
// // the shutdown may have caused the exception - ignore it
// }
// else
// {
// // we are still a go; report it
// logger.error("Reindex failure", e);
// }
// }
// }
// }
// }
//
// /**
// * @return Returns the number of documents reindexed
// */
// private int reindexMissingContent()
// {
// int count = 0;
// for (StoreRef storeRef : storeRefs)
// {
// count += reindexMissingContent(storeRef);
// }
// return count;
// }
//
// /**
// * @param storeRef the store to check for missing content
// * @return Returns the number of documents reindexed
// */
// private int reindexMissingContent(StoreRef storeRef)
// {
// SearchParameters sp = new SearchParameters();
// sp.addStore(storeRef);
//
// // search for it in the index
// String query = "TEXT:" + LuceneIndexerImpl.NOT_INDEXED_CONTENT_MISSING;
// sp.setLanguage(SearchService.LANGUAGE_LUCENE);
// sp.setQuery(query);
// ResultSet results = null;
// try
// {
// results = searcher.query(sp);
//
// int count = 0;
// // loop over the results and get the details of the nodes that have missing content
// List<ChildAssociationRef> assocRefs = results.getChildAssocRefs();
// for (ChildAssociationRef assocRef : assocRefs)
// {
// final NodeRef childNodeRef = assocRef.getChildRef();
// // prompt for a reindex - it might fail again, but we just keep plugging away
// TransactionWork<Object> reindexWork = new TransactionWork<Object>()
// {
// public Object doWork()
// {
// indexer.updateNode(childNodeRef);
// return null;
// }
// };
// TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork);
// count++;
// }
// // done
// if (logger.isDebugEnabled())
// {
// logger.debug("Reindexed missing content: \n" +
// " store: " + storeRef + "\n" +
// " node count: " + count);
// }
// return count;
// }
// finally
// {
// if (results != null)
// {
// results.close();
// }
// }
// }
//
// /**
// * @return Returns the transaction ID just reindexed, i.e. where some work was performed
// */
// private List<String> reindexNodes()
// {
// // get a list of all transactions still requiring a check
// List<String> txnsToCheck = getNextChangeTxnIds(FullIndexRecoveryComponent.currentTxnId);
//
// // loop over each transaction
// for (String changeTxnId : txnsToCheck)
// {
// reindexNodes(changeTxnId);
// }
//
// // done
// return txnsToCheck;
// }
//
// /**
// * Reindexes changes specific to the change transaction ID.
// * <p>
// * <b>All exceptions are absorbed.</b>
// */
// private void reindexNodes(final String changeTxnId)
// {
// /*
// * This must execute each within its own transaction.
// * The cache size is therefore not an issue.
// */
// TransactionWork<Object> reindexWork = new TransactionWork<Object>()
// {
// public Object doWork() throws Exception
// {
// // perform the work in a Hibernate callback
// HibernateCallback callback = new ReindexCallback(changeTxnId);
// getHibernateTemplate().execute(callback);
// // done
// return null;
// }
// };
// try
// {
// TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork);
// }
// catch (Throwable e)
// {
// logger.error("Transaction reindex failed: \n" +
// " txn: " + changeTxnId,
// e);
// }
// finally
// {
// // Up the current transaction now, in case the process fails at this point.
// // This will prevent the transaction from being processed again.
// // This applies to failures as well, which should be dealt with externally
// // and having the entire process start again, e.g. such as a system reboot
// currentTxnId = changeTxnId;
// }
// }
//
// /**
// * Stateful inner class that implements a single reindex call for a given store
// * and transaction.
// * <p>
// * It must be called within its own transaction.
// *
// * @author Derek Hulley
// */
// private class ReindexCallback implements HibernateCallback
// {
// private final String changeTxnId;
//
// public ReindexCallback(String changeTxnId)
// {
// this.changeTxnId = changeTxnId;
// }
//
// /**
// * Changes the L2 cache usage before reindexing for each store
// *
// * @see #reindexNodes(StoreRef, String)
// */
// public Object doInHibernate(Session session)
// {
// // set the way the L2 cache is used
// getSession().setCacheMode(l2CacheMode);
//
// // reindex each store
// for (StoreRef storeRef : storeRefs)
// {
// if (!nodeService.exists(storeRef))
// {
// // the store is not present
// continue;
// }
// // reindex for store
// reindexNodes(storeRef, changeTxnId);
// }
// // done
// return null;
// }
//
// private void reindexNodes(StoreRef storeRef, String changeTxnId)
// {
// // check if we need to perform this operation
// SearchParameters sp = new SearchParameters();
// sp.addStore(storeRef);
//
// // search for it in the index
// String query = "TX:\"" + changeTxnId + "\"";
// sp.setLanguage(SearchService.LANGUAGE_LUCENE);
// sp.setQuery(query);
// ResultSet results = null;
// try
// {
// results = searcher.query(sp);
// // did the index have any of these changes?
// if (results.length() > 0)
// {
// // the transaction has an entry in the index - assume that it was
// // atomically correct
// if (logger.isDebugEnabled())
// {
// logger.debug("Transaction present in index - no indexing required: \n" +
// " store: " + storeRef + "\n" +
// " txn: " + changeTxnId);
// }
// return;
// }
// }
// finally
// {
// if (results != null)
// {
// results.close();
// }
// }
// // the index has no record of this
// // were there any changes, or is it all just deletions?
// int changedCount = getChangedNodeStatusesCount(storeRef, changeTxnId);
// if (changedCount == 0)
// {
// // no nodes were changed in the transaction, i.e. they are only deletions
// // the index is quite right not to have any entries for the transaction
// if (logger.isDebugEnabled())
// {
// logger.debug("Transaction only has deletions - no indexing required: \n" +
// " store: " + storeRef + "\n" +
// " txn: " + changeTxnId);
// }
// return;
// }
//
// // process the deletions relevant to the txn and the store
// List<NodeStatus> deletedNodeStatuses = getDeletedNodeStatuses(storeRef, changeTxnId);
// for (NodeStatus status : deletedNodeStatuses)
// {
// NodeRef nodeRef = new NodeRef(storeRef, status.getKey().getGuid());
// // only the child node ref is relevant
// ChildAssociationRef assocRef = new ChildAssociationRef(
// ContentModel.ASSOC_CHILDREN,
// null,
// null,
// nodeRef);
// indexer.deleteNode(assocRef);
// }
//
// // process additions
// List<NodeStatus> changedNodeStatuses = getChangedNodeStatuses(storeRef, changeTxnId);
// for (NodeStatus status : changedNodeStatuses)
// {
// NodeRef nodeRef = new NodeRef(storeRef, status.getKey().getGuid());
// // get the primary assoc for the node
// ChildAssociationRef primaryAssocRef = nodeService.getPrimaryParent(nodeRef);
// // reindex
// indexer.createNode(primaryAssocRef);
// }
//
// // done
// if (logger.isDebugEnabled())
// {
// logger.debug("Transaction reindexed: \n" +
// " store: " + storeRef + "\n" +
// " txn: " + changeTxnId + "\n" +
// " deletions: " + deletedNodeStatuses.size() + "\n" +
// " modifications: " + changedNodeStatuses.size());
// }
// }
// };
//
// /**
// * Retrieve all transaction IDs that are greater than the given transaction ID.
// *
// * @param currentTxnId the transaction ID that must be less than all returned results
// * @return Returns an ordered list of transaction IDs
// */
// @SuppressWarnings("unchecked")
// public List<String> getNextChangeTxnIds(final String currentTxnId)
// {
// HibernateCallback callback = new HibernateCallback()
// {
// public Object doInHibernate(Session session)
// {
// Query query = session.getNamedQuery(QUERY_GET_NEXT_CHANGE_TXN_IDS);
// query.setString("currentTxnId", currentTxnId)
// .setReadOnly(true);
// return query.list();
// }
// };
// List<String> queryResults = (List<String>) getHibernateTemplate().execute(callback);
// // done
// return queryResults;
// }
//
// @SuppressWarnings("unchecked")
// public int getChangedNodeStatusesCount(final StoreRef storeRef, final String changeTxnId)
// {
// HibernateCallback callback = new HibernateCallback()
// {
// public Object doInHibernate(Session session)
// {
// Query query = session.getNamedQuery(QUERY_GET_CHANGED_NODE_STATUSES_COUNT);
// query.setString("storeProtocol", storeRef.getProtocol())
// .setString("storeIdentifier", storeRef.getIdentifier())
// .setString("changeTxnId", changeTxnId)
// .setReadOnly(true);
// return query.uniqueResult();
// }
// };
// Integer changeCount = (Integer) getHibernateTemplate().execute(callback);
// // done
// return changeCount.intValue();
// }
//
// @SuppressWarnings("unchecked")
// public List<NodeStatus> getChangedNodeStatuses(final StoreRef storeRef, final String changeTxnId)
// {
// HibernateCallback callback = new HibernateCallback()
// {
// public Object doInHibernate(Session session)
// {
// Query query = session.getNamedQuery(QUERY_GET_CHANGED_NODE_STATUSES);
// query.setString("storeProtocol", storeRef.getProtocol())
// .setString("storeIdentifier", storeRef.getIdentifier())
// .setString("changeTxnId", changeTxnId)
// .setReadOnly(true);
// return query.list();
// }
// };
// List<NodeStatus> queryResults = (List) getHibernateTemplate().execute(callback);
// // done
// return queryResults;
// }
//
// @SuppressWarnings("unchecked")
// public List<NodeStatus> getDeletedNodeStatuses(final StoreRef storeRef, final String changeTxnId)
// {
// HibernateCallback callback = new HibernateCallback()
// {
// public Object doInHibernate(Session session)
// {
// Query query = session.getNamedQuery(QUERY_GET_DELETED_NODE_STATUSES);
// query.setString("storeProtocol", storeRef.getProtocol())
// .setString("storeIdentifier", storeRef.getIdentifier())
// .setString("changeTxnId", changeTxnId)
// .setReadOnly(true);
// return query.list();
// }
// };
// List<NodeStatus> queryResults = (List) getHibernateTemplate().execute(callback);
// // done
// return queryResults;
// }
//}

View File

@@ -307,23 +307,6 @@ public class IntegrityTest extends TestCase
logger.error("Method commented out: testRemoveSourcesOfMandatoryAssocs");
}
public void testDuplicateTargetAssocs() throws Exception
{
NodeRef parent = createNode("source", TEST_TYPE_WITH_CHILD_ASSOCS, null);
NodeRef child1 = createNode("child1", TEST_TYPE_WITHOUT_ANYTHING, null);
NodeRef child2 = createNode("child2", TEST_TYPE_WITHOUT_ANYTHING, null);
NodeRef child3 = createNode("child3", TEST_TYPE_WITHOUT_ANYTHING, null);
// satisfy the one-to-one
nodeService.addChild(parent, child3, TEST_ASSOC_CHILD_ONE_ONE, QName.createQName(NAMESPACE, "mandatoryChild"));
// create the non-duplicate assocs
nodeService.addChild(parent, child1, TEST_ASSOC_CHILD_ZEROMANY_ZEROMANY, QName.createQName(NAMESPACE, "dupli_cate"));
nodeService.addChild(parent, child2, TEST_ASSOC_CHILD_ZEROMANY_ZEROMANY, QName.createQName(NAMESPACE, "dupli_cate"));
checkIntegrityExpectFailure("Failed to detect duplicate association names", 1);
}
public void testCreateSourceOfAssocsWithMandatoryTargetsPresent() throws Exception
{
NodeRef source = createNode("abc", TEST_TYPE_WITH_ASSOCS, null);

View File

@@ -21,6 +21,7 @@ package org.alfresco.service;
*
* @author Andy Hind
*/
@PublicService
public interface AnnotationTestInterface
{
@Auditable()

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.service;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specifically indicate that an interface defines a public service.
*
* This is a marker annotation.
*
* @author Andy Hind
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PublicService
{
}

View File

@@ -52,6 +52,7 @@ import org.alfresco.service.transaction.TransactionService;
*
* @author David Caruana
*/
@PublicService
public interface ServiceRegistry
{
// Service Bean Names

View File

@@ -21,6 +21,7 @@ import java.util.List;
import java.util.Map;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.NodeRef;
/**
@@ -28,6 +29,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
*
* @author Roy Wetherall
*/
@PublicService
public interface ActionService
{
/**

View File

@@ -18,12 +18,15 @@ package org.alfresco.service.cmr.admin;
import java.util.List;
import org.alfresco.service.PublicService;
/**
* General administration tasks and system information.
*
* @since 1.2
* @author Derek Hulley
*/
@PublicService
public interface AdminService
{
// public List<PatchInfo> getPatches();

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.service.cmr.audit;
import org.alfresco.service.NotAuditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* The public API by which applications can create audit entries.
* This does not affect auditing using method interceptors.
* The information recorded can not be confused between the two.
*
* This API could be used by an audit action.
*
* @author Andy Hind
*/
@PublicService
public interface AuditService
{
/**
* Add an application audit entry.
*
* @param source -
* a string that represents the application
* @param description -
* the audit entry
*/
@NotAuditable
public void audit(String source, String description);
/**
*
* @param source -
* a string that represents the application
* @param description -
* the audit entry
* @param key -
* a node ref to use as the key for filtering etc
*/
@NotAuditable
public void audit(String source, String description, NodeRef key);
/**
*
* @param source -
* a string that represents the application
* @param description -
* the audit entry
* @param args -
* an arbitrary list of parameters
*/
@NotAuditable
public void audit(String source, String description, Object... args);
/**
*
* @param source -
* a string that represents the application
* @param description -
* the audit entry *
* @param key -
* a node ref to use as the key for filtering etc
* @param args -
* an arbitrary list of parameters
*/
@NotAuditable
public void audit(String source, String description, NodeRef key, Object... args);
}

View File

@@ -20,6 +20,7 @@ import java.io.Serializable;
import java.util.Map;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
@@ -29,6 +30,7 @@ import org.alfresco.service.namespace.QName;
*
* @author Roy Wetherall
*/
@PublicService
public interface CheckOutCheckInService
{
/**

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.dictionary;
import java.util.Collection;
import org.alfresco.service.NotAuditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.namespace.QName;
@@ -35,6 +36,7 @@ import org.alfresco.service.namespace.QName;
*
* @author David Caruana
*/
@PublicService
public interface DictionaryService
{

View File

@@ -20,6 +20,7 @@ import java.util.Collection;
import java.util.List;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -29,6 +30,7 @@ import org.alfresco.service.cmr.repository.StoreRef;
*
* @author Roy Wetherall
*/
@PublicService
public interface LockService
{
/**

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.model;
import java.util.List;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -32,6 +33,7 @@ import org.alfresco.service.namespace.QName;
*
* @author Derek Hulley
*/
@PublicService
public interface FileFolderService
{
/**

View File

@@ -18,6 +18,7 @@ package org.alfresco.service.cmr.repository;
import org.alfresco.repo.content.transform.ContentTransformer;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
import org.alfresco.service.namespace.QName;
@@ -42,6 +43,7 @@ import org.alfresco.service.namespace.QName;
*
* @author Derek Hulley
*/
@PublicService
public interface ContentService
{
/**

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.repository;
import java.util.List;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.namespace.QName;
/**
@@ -29,6 +30,7 @@ import org.alfresco.service.namespace.QName;
*
* @author Roy Wetherall
*/
@PublicService
public interface CopyService
{
/**

View File

@@ -21,6 +21,7 @@ import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.NotAuditable;
import org.alfresco.service.PublicService;
/**
@@ -29,6 +30,7 @@ import org.alfresco.service.NotAuditable;
* @author Derek Hulley
*
*/
@PublicService
public interface MimetypeService
{
/**

View File

@@ -22,6 +22,7 @@ import java.util.Map;
import java.util.Set;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.dictionary.InvalidAspectException;
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
import org.alfresco.service.namespace.QName;
@@ -32,6 +33,7 @@ import org.alfresco.service.namespace.QNamePattern;
*
* @author Derek Hulley
*/
@PublicService
public interface NodeService
{
/**

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.repository;
import java.util.Map;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.namespace.QName;
/**
@@ -36,6 +37,7 @@ import org.alfresco.service.namespace.QName;
*
* @author Kevin Roast
*/
@PublicService
public interface ScriptService
{
/**

View File

@@ -671,8 +671,7 @@ public final class TemplateNode implements Serializable
if (this.services.getNodeService().exists(nodeRef))
{
return "Node Type: " + getType() +
"\nNode Properties: " + this.getProperties().toString() +
"\nNode Aspects: " + this.getAspects().toString();
"\tNode Ref: " + this.nodeRef.toString();
}
else
{

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.repository;
import java.io.Writer;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
/**
* Template Service.
@@ -34,6 +35,7 @@ import org.alfresco.service.Auditable;
*
* @author Kevin Roast
*/
@PublicService
public interface TemplateService
{
/**

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.rule;
import java.util.List;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -27,6 +28,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
*
* @author Roy Wetherall
*/
@PublicService
public interface RuleService
{
/**

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.search;
import java.util.Collection;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -37,6 +38,7 @@ import org.alfresco.service.namespace.QName;
* @author Andy Hind
*
*/
@PublicService
public interface CategoryService
{
/**

View File

@@ -20,6 +20,7 @@ import java.io.Serializable;
import java.util.List;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
@@ -38,6 +39,7 @@ import org.alfresco.service.namespace.QName;
* @author Andy hind
*
*/
@PublicService
public interface SearchService
{
public static final String LANGUAGE_LUCENE = "lucene";

View File

@@ -20,6 +20,7 @@ import java.util.Set;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
/**
* The authentication service defines the API for managing authentication information
@@ -28,6 +29,7 @@ import org.alfresco.service.Auditable;
* @author Andy Hind
*
*/
@PublicService
public interface AuthenticationService
{
/**

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.security;
import java.util.Set;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
/**
* The service that encapsulates authorities granted to users.
@@ -34,6 +35,7 @@ import org.alfresco.service.Auditable;
*
* @author Andy Hind
*/
@PublicService
public interface AuthorityService
{
/**

View File

@@ -17,6 +17,7 @@
package org.alfresco.service.cmr.security;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.NodeRef;
/**
@@ -24,6 +25,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
*
* @author Andy Hind
*/
@PublicService
public interface OwnableService
{
/**

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.security;
import java.util.Set;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
@@ -29,6 +30,7 @@ import org.alfresco.service.namespace.QName;
*
* @author Andy Hind
*/
@PublicService
public interface PermissionService
{
public static final String ROLE_PREFIX = "ROLE_";

View File

@@ -21,6 +21,7 @@ import java.util.Map;
import java.util.Set;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
@@ -36,6 +37,7 @@ import org.alfresco.service.namespace.QName;
*
* @author Andy Hind
*/
@PublicService
public interface PersonService
{
/**

View File

@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.Map;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.AspectMissingException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -31,6 +32,7 @@ import org.alfresco.service.namespace.QName;
*
* @author Roy Wetherall
*/
@PublicService
public interface VersionService
{
/**

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.view;
import java.io.OutputStream;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
/**
@@ -26,6 +27,7 @@ import org.alfresco.service.Auditable;
*
* @author David Caruana
*/
@PublicService
public interface ExporterService
{
/**

View File

@@ -19,6 +19,7 @@ package org.alfresco.service.cmr.view;
import java.io.Reader;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
/**
@@ -27,6 +28,7 @@ import org.alfresco.service.Auditable;
* @author David Caruana
*
*/
@PublicService
public interface ImporterService
{

Some files were not shown because too many files have changed in this diff Show More