/* * 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.AuditState; 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 = new ThreadLocal(); private ThreadLocal auditConfigImplId = new ThreadLocal(); private ThreadLocal auditDateImplId = new ThreadLocal(); private ThreadLocal> sourceIds = new ThreadLocal>(); 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) { // 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(AuditState auditInfo) { AuditSourceImpl auditSourceImpl; SourceKey sourceKey = new SourceKey(auditInfo.getAuditApplication(), auditInfo.getAuditService(), auditInfo.getAuditMethod()); if(sourceIds.get() == null) { sourceIds.set(new HashMap()); } 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(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(); 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(AuditState 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(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 Session 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; } } }