All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openmdx.audit2.aop0.PlugIn_1 Maven / Gradle / Ivy

There is a newer version: 2.18.10
Show newest version
/*
 * ====================================================================
 * Project:     openMDX, http://www.openmdx.org/
 * Description: Audit Plug-In
 * Owner:       OMEX AG, Switzerland, http://www.omex.ch
 * ====================================================================
 *
 * This software is published under the BSD license as listed below.
 * 
 * Copyright (c) 2009-2014, OMEX AG, Switzerland
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 * * Neither the name of the openMDX team nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * ------------------
 * 
 * This product includes or is based on software developed by other 
 * organizations as listed in the NOTICE file.
 */
package org.openmdx.audit2.aop0;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.jdo.ObjectState;
import javax.jdo.PersistenceManager;

import org.openmdx.audit2.spi.Configuration;
import org.openmdx.audit2.spi.InvolvementPersistence;
import org.openmdx.audit2.spi.Qualifiers;
import org.openmdx.base.accessor.cci.Container_1_0;
import org.openmdx.base.accessor.cci.DataObject_1_0;
import org.openmdx.base.accessor.cci.SystemAttributes;
import org.openmdx.base.accessor.rest.DataObjectManager_1;
import org.openmdx.base.accessor.rest.DataObject_1;
import org.openmdx.base.accessor.rest.UnitOfWork_1;
import org.openmdx.base.aop0.PlugIn_1_0;
import org.openmdx.base.aop0.UpdateAvoidance;
import org.openmdx.base.aop0.UpdateAvoidance_1;
import org.openmdx.base.exception.ServiceException;
import org.openmdx.base.mof.cci.ModelElement_1_0;
import org.openmdx.base.naming.Path;
import org.openmdx.base.persistence.cci.UserObjects;
import org.openmdx.kernel.exception.BasicException;

/**
 * Audit Plug-In
 * 

* Note:
* Together with this plug-in one should use * {@link org.openmdx.base.aop0.PlugIn_1} rather than * {@link org.openmdx.base.aop0.UpdateAvoidance_1}. *
*/ public class PlugIn_1 implements Configuration, PlugIn_1_0 { /** * The audit segment */ private Path auditSegmentId; /** * The XRI pattern of the objects to be audited */ protected Path[] dataPrefix; /** * The XRI pattern of the before images */ protected Path[] auditPrefix; /** * The XRI pattern of the objects not to be audited */ protected Path[] exclusionPattern = new Path[]{}; /** * The involvement persistence mode */ private InvolvementPersistence involvementPersistence = InvolvementPersistence.STANDARD; /** * States of objects involved in a unit of work */ private static final EnumSet involvedStatesForInvolvementPersistenceEmbedded = EnumSet.of( ObjectState.PERSISTENT_DIRTY, ObjectState.PERSISTENT_DELETED ); /** * Pattern to validate a segment XRI */ private static final Path SEGMENT_PATTERN = new Path( "xri://@openmdx*($..)/provider/($..)/segment/($..)" ); /** * Maps the data paths to audit paths */ private final Map mapping = new AbstractMap() { Set> entries = new AbstractSet>() { @Override public Iterator> iterator() { return new Iterator>() { protected int cursor = 0; public boolean hasNext() { return this.cursor < PlugIn_1.this.dataPrefix.length; } public java.util.Map.Entry next() { return new java.util.Map.Entry() { private final int index = cursor++; public Path getKey() { return PlugIn_1.this.dataPrefix[index]; } public Path getValue() { return PlugIn_1.this.auditPrefix[index]; } public Path setValue(Path value) { throw new UnsupportedOperationException(); } }; } public void remove() { throw new UnsupportedOperationException(); } }; } @Override public int size() { return PlugIn_1.this.dataPrefix.length; } }; @Override public Set> entrySet() { return this.entries; } }; /* (non-Javadoc) * @see org.openmdx.base.aop0.PlugIn_1_0#getPlugInObject(java.lang.Class) */ @Override public T getPlugInObject(Class type) { return Configuration.class == type ? type.cast(this) : UpdateAvoidance.class == type ? type.cast(UpdateAvoidance_1.plugInObject) : null; } /** * Internalize a pattern resource identifier * * @param value * an XRI's String representation * @return an XRI's Path representation */ protected Path toPattern(String value) { if (value != null) { Path pattern = new Path(value); if(pattern.isPattern()) { return pattern; } } throw BasicException.initHolder( new IllegalArgumentException( "Valid pattern expected", BasicException.newEmbeddedExceptionStack( BasicException.Code.DEFAULT_DOMAIN, BasicException.Code.BAD_PARAMETER, new BasicException.Parameter(BasicException.Parameter.XRI, value) ) ) ); } /** * Internalize a prefix resource identifier * * @param value * an XRI's String representation * @return an XRI's Path representation */ protected Path toPrefix(String value) { if (value != null) { Path candidate = new Path(value); if (candidate.toXRI().endsWith("/($...)")) { // TODO simplify Path parent = candidate.getParent(); if (!parent.isPattern()) { return parent; } } } throw BasicException.initHolder( new IllegalArgumentException( "Valid segment starts-with pattern expected", BasicException.newEmbeddedExceptionStack( BasicException.Code.DEFAULT_DOMAIN, BasicException.Code.BAD_PARAMETER, new BasicException.Parameter(BasicException.Parameter.XRI, value) ) ) ); } /** * Validate a segment identifier * * @param value * an XRI's String representation * * @return an XRI's Path representation */ protected Path toSegmentIdentifier(String value) { if (value != null) { Path candidate = new Path(value); if (candidate.isLike(SEGMENT_PATTERN)) { return candidate; } } throw BasicException.initHolder(new IllegalArgumentException( "Valid segment path expected", BasicException.newEmbeddedExceptionStack( BasicException.Code.DEFAULT_DOMAIN, BasicException.Code.BAD_PARAMETER, new BasicException.Parameter(BasicException.Parameter.XRI, value)))); } /** * Externalize a resource identifier * * @param value * an XRI's Path representation * @param prefix * * @return an XRI's String representation */ protected String toXRI(Path value, boolean prefix) { return value == null ? null : prefix ? value.toXRI() + "/($...)" : value.toXRI(); } /** * Retrieve auditSegment. * * @return Returns the auditSegment. */ public String getAuditSegment() { return toXRI(this.auditSegmentId, false); } /** * Set auditSegment. * * @param auditSegment * The auditSegment to set. */ public void setAuditSegment(String auditSegment) { this.auditSegmentId = toSegmentIdentifier(auditSegment); } /** * Set the object id patterns for the objects to be audited * * @param value * the object id patterns for the objects to be audited */ public void setDataPattern(String[] value) { this.dataPrefix = new Path[value.length]; int i = 0; for (String dataPattern : value) { this.dataPrefix[i++] = toPrefix(dataPattern); } } /** * Retrieve the object id patterns for the objects to be audited * * @return the object id patterns for the objects to be audited */ public String[] getDataPattern() { String[] dataPattern = new String[this.dataPrefix.length]; int i = 0; for (Path value : this.dataPrefix) { dataPattern[i++] = toXRI(value, true); } return dataPattern; } /** * Set an object id patterns for objects to be audited * * @param index * @param value */ public void setDataPattern(int index, String value) { this.dataPrefix[index] = toPrefix(value); } /** * Get an object id patterns for objects to be audited * * @param index * * @return an object id patterns for objects to be audited */ public String getDataPattern(int index) { return toXRI(this.dataPrefix[index], true); } /** * Set the object id patterns for the before images * * @param value * the object id patterns for the before images */ public void setAuditPattern(String[] value) { this.auditPrefix = new Path[value.length]; int i = 0; for (String auditPattern : value) { this.auditPrefix[i++] = toPrefix(auditPattern); } } /** * Retrieve the object id patterns for the before images * * @return the object id patterns for the before images */ public String[] getAuditPattern() { String[] auditPattern = new String[this.auditPrefix.length]; int i = 0; for (Path value : this.auditPrefix) { auditPattern[i++] = toXRI(value, true); } return auditPattern; } /** * Set an object id patterns for the before image * * @param index * @param value */ public void setAuditPattern(int index, String value) { this.auditPrefix[index] = toPrefix(value); } /** * Get an object id patterns for the before image * * @param index * * @return an object id patterns for the before image */ public String getAuditPattern(int index) { return toXRI(this.auditPrefix[index], true); } /** * Set the object id patterns for the objects not to be audited * * @param value * the object id patterns for the objects not to be audited */ public void setExclusionPattern(String[] value) { this.exclusionPattern = new Path[value.length]; int i = 0; for (String exclusionPattern : value) { this.exclusionPattern[i++] = toPattern(exclusionPattern); } } /** * Retrieve the object id patterns for the objects not to be audited * * @return the object id patterns for the objects not to be audited */ public String[] getExclusionPattern() { String[] exclusionPattern = new String[this.dataPrefix.length]; int i = 0; for (Path value : this.exclusionPattern) { exclusionPattern[i++] = toXRI(value, false); } return exclusionPattern; } /** * Set an object id patterns for objects not to be audited * * @param index * @param value */ public void setExclusionPattern(int index, String value) { this.exclusionPattern[index] = toPattern(value); } /** * Get an object id patterns for objects not to be audited * * @param index * * @return an object id patterns for objects not to be audited */ public String getExclusionPattern(int index) { return toXRI(this.exclusionPattern[index], false); } /** * Retrieve involvementPersistence. * * @return Returns the involvementPersistence. */ public String getInvolvementPersistence() { return this.involvementPersistence.name(); } /** * Set involvementPersistence. * * @param involvementPersistence The involvementPersistence to set. */ public void setInvolvementPersistence( String involvementPersistence ) { this.involvementPersistence = InvolvementPersistence.valueOf(involvementPersistence); } /* (non-Javadoc) * @see org.openmdx.audit2.spi.Configuration#getPersistenceMode() */ @Override public InvolvementPersistence getPersistenceMode() { return this.involvementPersistence; } /* (non-Javadoc) * @see org.openmdx.audit2.spi.Configuration#getMapping() */ @Override public Map getMapping() { return this.mapping; } /* (non-Javadoc) * @see org.openmdx.audit2.spi.Configuration#getAuditSegmentId() */ @Override public Path getAuditSegmentId( PersistenceManager context ) { return this.auditSegmentId; } // ------------------------------------------------------------------------ // Implements PlugIn_1_0 // ------------------------------------------------------------------------ /* * (non-Javadoc) * * @see * org.openmdx.base.aop0.PlugIn_1_0#getQualifier(org.openmdx.base.accessor * .rest.DataObject_1, java.lang.String) */ @Override public String getQualifier(DataObject_1 object, String qualifier) throws ServiceException { return qualifier; } /* * (non-Javadoc) * * @see * org.openmdx.base.aop0.PlugIn_1_0#setCore(org.openmdx.base.accessor.rest * .DataObject_1, org.openmdx.base.accessor.rest.DataObject_1) */ @Override public void postSetCore( DataObject_1 target, DataObject_1 core ) throws ServiceException { // nothing to do } /** * Tests whether a given object shall be audited * * @param candidate * the object to be tested * * @return the matching index if the object is involved, -1 otherwise * @throws ServiceException */ protected int getMatchingIndex( DataObject_1 candidate ) throws ServiceException { if ( this.dataPrefix != null && candidate.jdoGetPersistenceManager().getModel().isInstanceof(candidate,"org:openmdx:base:Modifiable") ) { Path path = candidate.jdoGetObjectId(); for(int i = 0; i < this.dataPrefix.length; i++) { if(path.startsWith(this.dataPrefix[i])) { for(Path exclusionPattern : this.exclusionPattern) { if(path.isLike(exclusionPattern)) { return -1; } } return i; } } } return -1; } /** * Tests whether a given object shall be audited * * @param candidate * the object to be tested * * @return true/code> if the candidate shall be audited * @throws ServiceException */ protected boolean isInvolved( DataObject_1 candidate ) throws ServiceException { return getMatchingIndex(candidate) >= 0; } /* * (non-Javadoc) * * @see org.openmdx.base.aop0.PlugIn_1_0#flush(UnitOfWork_1,boolean) */ @Override public void flush( UnitOfWork_1 unitOfWork, boolean beforeCompletion ) { try { DataObjectManager_1 persistenceManager = (DataObjectManager_1) unitOfWork.getPersistenceManager(); Map auditBeforeImages = new HashMap(); for (Object managedObject : persistenceManager.getManagedObjects(involvedStatesForInvolvementPersistenceEmbedded)) { DataObject_1 candidate = (DataObject_1) managedObject; if(this.getMatchingIndex(candidate) < 0) { // // Objects without audit // if(unitOfWork.isUpdateAvoidanceEnabled() && !candidate.jdoIsDeleted()){ candidate.makePersistentCleanWhenUnmodified(); } } else { // // Objects with audit // DataObject_1 beforeImage = candidate.getBeforeImage(); // do not in-line! if(beforeImage != null && !beforeImage.jdoIsPersistent()) { if( candidate.jdoIsDeleted() || candidate.thereRemainDirtyFeaturesAfterRemovingTheUnmodifiedOnes(beforeImage) || !unitOfWork.isUpdateAvoidanceEnabled() ){ auditBeforeImages.put( Qualifiers.getAudit2BeforeImageId( this, candidate.jdoGetObjectId(), unitOfWork.getUnitOfWorkIdentifier() ), beforeImage ); } else { candidate.evictUnconditionally(); } } } } if(!auditBeforeImages.isEmpty()) { if(this.involvementPersistence != InvolvementPersistence.EMBEDDED) { throw new UnsupportedOperationException("Persistence modes other than EMBEDDED are not yet supported"); } DataObject_1_0 auditSegment = persistenceManager.getObjectById(this.getAuditSegmentId(persistenceManager)); String unitOfWorkId = unitOfWork.getUnitOfWorkIdentifier(); Container_1_0 unitOfWorkContainer = auditSegment.objGetContainer("unitOfWork"); if(!unitOfWorkContainer.containsKey(unitOfWorkId)){ DataObject_1_0 auditUnitOfWork = persistenceManager.newInstance("org:openmdx:audit2:UnitOfWork", null); auditUnitOfWork.objSetValue("taskId", unitOfWork.getTaskIdentifier()); auditUnitOfWork.objSetValue(SystemAttributes.CREATED_AT, unitOfWork.getTransactionTime()); auditUnitOfWork.objGetList(SystemAttributes.CREATED_BY).addAll(UserObjects.getPrincipalChain(persistenceManager)); auditUnitOfWork.objMove( unitOfWorkContainer, unitOfWorkId ); } for(Map.Entry auditBeforeImage : auditBeforeImages.entrySet()){ auditBeforeImage.getValue().makePersistent( auditBeforeImage.getKey(), false // already flushed ); } } } catch (ServiceException exception) { throw new javax.jdo.JDOUserCallbackException( "audit2's flush() callback failed", exception ); } } /* (non-Javadoc) * @see org.openmdx.base.aop0.PlugIn_1_0#callbackOnCascadedDeletes() */ @Override public boolean requiresCallbackOnCascadedDelete( DataObject_1 object ) throws ServiceException { return this.isInvolved(object); } /* (non-Javadoc) * @see org.openmdx.base.aop0.PlugIn_1_0#isExemptFromValidation(org.openmdx.base.mof.cci.ModelElement_1_0) */ @Override public boolean isExemptFromValidation(DataObject_1 object, ModelElement_1_0 feature) throws ServiceException { return false; } /* (non-Javadoc) * @see org.openmdx.base.aop0.PlugIn_1_0#isAspect(org.openmdx.base.accessor.rest.DataObject_1) */ @Override public Boolean isAspect(DataObject_1 object) { return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy