2006-09-04 19:12:55 +00:00

494 lines
17 KiB
Java

/*
* 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.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.audit.AuditConfiguration;
import org.alfresco.repo.audit.AuditDAO;
import org.alfresco.repo.audit.AuditException;
import org.alfresco.repo.audit.AuditState;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.TransactionalDao;
import org.alfresco.service.cmr.audit.AuditInfo;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
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";
public static final String QUERY_AUDIT_TRAIL = "audit.GetAuditTrailForNode";
public static final String QUERY_AUDIT_PROTOCOL = "protocol";
public static final String QUERY_AUDIT_STORE_ID = "store_id";
public static final String QUERY_AUDIT_NODE_ID = "node_id";
/** 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(AuditState auditInfo)
{
if(AuthenticationUtil.getCurrentUserName() == null)
{
AuthenticationUtil.setSystemUserAsCurrentUser();
try
{
audit0(auditInfo);
}
finally
{
AuthenticationUtil.clearCurrentSecurityContext();
}
}
else
{
audit0(auditInfo);
}
}
private void audit0(AuditState auditInfo)
{
// Find/Build the configuraton entry
AuditConfig auditConfig = getAuditConfig(auditInfo);
// Find/Build any dates
AuditDate auditDate = getAuditDate(auditInfo);
// Find/Build the source
AuditSource 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 AuditSource getAuditSource(AuditState auditInfo)
{
AuditSource 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 = (AuditSource) 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 AuditDate getAuditDate(AuditState 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();
AuditDate 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 = (AuditDate) 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 AuditConfig getAuditConfig(AuditState auditInfo)
{
AuditConfig 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 = (AuditConfig) getSession()
.get(AuditConfigImpl.class, auditConfigImplId.get().longValue());
if (auditConfig == null)
{
auditConfig = createNewAuditConfigImpl(auditInfo);
}
}
return auditConfig;
}
private AuditConfigImpl createNewAuditConfigImpl(AuditState 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;
}
}
public List<AuditInfo> getAuditTrail(NodeRef nodeRef)
{
if(nodeRef == null)
{
return Collections.<AuditInfo>emptyList();
}
List<? extends AuditFact> internalTrail = AuditFactImpl.getAuditTrail(getSession(), nodeRef);
ArrayList<AuditInfo> answer = new ArrayList<AuditInfo>(internalTrail.size());
for(AuditFact auditFact : internalTrail)
{
AuditInfo info = new AuditInfoImpl(auditFact);
answer.add(info);
}
return answer;
}
}