Results 1 to 5 of 5

Thread: History tables and error logging

  1. #1
    Join Date
    Aug 2004
    Location
    Ankara, Turkey
    Posts
    24

    Default History tables and error logging

    Hi,
    [I hope this is the right forum]
    I need to track all updates to the database in my application. I mean, all versions of a record must be kept.
    For example, in my DAO, if I have a method like
    Code:
    public User update_updateUser(User user) {
      getHibernateTemplate().saveOrUpdate(user);
    }
    I want to make this run as:
    Code:
    public User update_updateUser(User user) {
      BackupUser backupUser=new BackupUser(User);
      getHibernateTemplate().save(backupUser);
      getHibernateTemplate().saveOrUpdate(user);
    }
    For each entity, I will need to create another entity (Like BackupUser), which maps to another database table (Like BACKUP_USER).

    I would like to learn if it is possible, by use of AOP, to have the functionality I mentioned above - without handcoding manually for each Hibernate call.

    Another similar requirement is error logging. Whenever Spring catches an Exception, I would like to run this code:
    Code:
    ApplicationErrorLog appErrorLog = new(ApplicationErrorLog);
    getHibernateTemplate().save(applicationErrorLog );
    I know that I have to read a lot about AOP, but until then, your help, simple code examples and appcontext.xml will be will be very much appreciated.

    Regards,
    Turgay Zengin

  2. #2
    Join Date
    Aug 2004
    Location
    Montréal, Canada
    Posts
    845

    Default

    did you consider using database triggers?
    Omar Irbouh

    Spring Modules Team
    http://irbouh.blogspot.com/

  3. #3
    Join Date
    Aug 2004
    Location
    Ankara, Turkey
    Posts
    24

    Default

    Right, the natural way to implement this is using an update trigger, but I do not want to go into database triggers, because I want the database to be portable.

    Regards,
    Turgay Zengin

  4. #4
    Join Date
    Aug 2004
    Location
    Ankara, Turkey
    Posts
    24

    Default

    This is what I could do, after studying AOP:

    SaveDatabaseInterceptor is for catching save operations, and then saving a backup object to the database. It works if the object implements Auditable --if(args0 instanceof Auditable)--, and if this is not a "insert into" but a "update" operation --if(oldId!=null)--.

    Code:
    public class SaveDatabaseInterceptor implements MethodInterceptor {
    	private SystemDAO systemDAO = null;
    
    	public void setSystemDAO(SystemDAO systemDao) {
            this.systemDAO = systemDao;
        }
    
    	public Object invoke(MethodInvocation invocation) throws Throwable {
    		Object[] args=invocation.getArguments();
    		Object args0=args[0];
    		if(args0 instanceof Auditable) {
    			BasePersistentObject bpo=(BasePersistentObject)args[0];
    			Long oldId=bpo.getId();
    			if(oldId!=null){				
    				BasePersistentObject backupBPO=bpo.getBackupObject();
    				systemDAO.saveBPO(backupBPO);
    				System.out.println("save advice worked!:" + invocation);
    			}		
    		}
    		Object rval = invocation.proceed();	
    		return rval;
    	}
    }
    Each Auditable entity class defines a method to get a "Backup" object. For example, in User.java:

    Code:
    	public BasePersistentObject getBackupObject() {
    		return new Backup_User(this);
    	}
    Backup_User is a seperate class, which also has a mapping file for hibernate.

    For "delete" operations, I have the following.

    Code:
    public class RemoveDatabaseInterceptor implements MethodInterceptor {
    	private SystemDAO systemDAO = null;
    
    	public void setSystemDAO(SystemDAO systemDao) {
            this.systemDAO = systemDao;
        }
    	
    	public Object invoke(MethodInvocation invocation) throws Throwable {	
    		Object[] args=invocation.getArguments();
    		Object args0=args[0];
    		if(args0 instanceof Auditable) {
    			BasePersistentObject bpo=(BasePersistentObject)args[0];
    			
    			if(bpo!=null){				
    				BasePersistentObject deletedBPO=bpo.getDeletedObject();
    				systemDAO.saveBPO(deletedBPO);
    				System.out.println("remove advice worked!:" + invocation);
    			}		
    		}
    
    		Object rval = invocation.proceed();	
    		return rval;
    		
    	}
    	
    }
    Likewise, each Auditable class has a method to get a "Deleted" object:
    Code:
    	public BasePersistentObject getDeletedObject() {
    		return new Deleted_User(this);
    	}
    Relevant parts from the applicationContext.xml:
    Code:
    	<bean id="DAOTemplate" lazy-init="true"
    		class="org.springframework.aop.framework.ProxyFactoryBean">
    		<property name="interceptorNames">
    			<list>
    				<value>saveDatabaseAdvisor</value>
    				<value>removeDatabaseAdvisor</value>
    			</list>
    		</property>
    	</bean>
    
        <bean id="userDAO" parent="DAOTemplate" >
    		<property name="proxyInterfaces"><value>dao.UserDAO</value></property>
    		<property name="target"><ref local="userDAOTarget"/></property>
        </bean>    
    
    	<bean id="userDAOTarget" class="dao.hibernate.UserDAOHibernate"> 
            <property name="sessionFactory"><ref local="sessionFactory"/></property>		
    	</bean>		
    
        <bean id="systemDAO" parent="DAOTemplate" >
    		<property name="proxyInterfaces"><value>dao.SystemDAO</value></property>
    		<property name="target"><ref local="systemDAOTarget"/></property>
        </bean>    
    
    	<bean id="systemDAOTarget" class="dao.hibernate.SystemDAOHibernate"> 
            <property name="sessionFactory"><ref local="sessionFactory"/></property>		
    	</bean>		
    
    	<bean id="saveDatabaseInterceptor" class="util.SaveDatabaseInterceptor">
    		<property name="systemDAO"><ref local="systemDAO"/></property>
    	</bean>
    
    	<bean id="saveDatabaseAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    		<property name="advice"><ref local="saveDatabaseInterceptor"/></property>
    		<property name="patterns">
    			<list>
    				<value>.*save.*</value>				
    			</list>			
    		</property>
    	</bean>
    
    	<bean id="removeDatabaseInterceptor" class="util.RemoveDatabaseInterceptor" >
    		<property name="systemDAO"><ref local="systemDAO"/></property>
    	</bean>
    	
    	<bean id="removeDatabaseAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    		<property name="advice"><ref local="removeDatabaseInterceptor"/></property>
    		<property name="patterns">
    			<list>
    				<value>.*remove.*</value>
    			</list>			
    		</property>
    	</bean>
    I now have only one problem with the remove operation. When the entity itself is deleted from the master table(User), a record will be inserted into the "Deleted_" table (Deleted_User). But I cannot put a foreign key to the "Deleted" table to point to the "deletedUser", because the record will be deleted from the master table...

    I am thinking about not deleting from the master table actually, but marking it as deleted, using a field called DATABASE_STATUS, and setting it to "DELETED". ("ACTIVE" if not deleted). But this also introduces another problem: If I have unique constraints on the table (USERNAME UNIQUE), than I cannot insert a new record violating that unique constraint. Any ideas?

    Regards,
    Turgay Zengin

  5. #5
    Join Date
    Aug 2004
    Location
    Ankara, Turkey
    Posts
    24

    Default

    Here is the design I came up with, hoping that it could be useful for others as well. Any comments, critiques, improvement suggestions are welcome.

    SaveDatabaseInterceptor is for catching save operations, and then saving a backup object to the database. It works if the object implements Auditable --if(args0 instanceof Auditable)--, and if this is not a "insert into" but a "update" operation --if(oldId!=null)--.
    Code:
    public class SaveDatabaseInterceptor implements MethodInterceptor &#123;
    	private SystemDAO systemDAO = null;
    	private static final Log log = LogFactory.getLog&#40;SaveDatabaseInterceptor.class&#41;;
    	
    	public void setSystemDAO&#40;SystemDAO systemDao&#41; &#123;
            this.systemDAO = systemDao;
        &#125;
    
    	public Object invoke&#40;MethodInvocation invocation&#41; throws Throwable &#123;
    		log.debug&#40;"save advice will work&#58;" + invocation&#41;;
    		BasePersistentObject bpo=null;
    		Object&#91;&#93; args=invocation.getArguments&#40;&#41;;
    		Object args0=args&#91;0&#93;;
    		if&#40;args0 instanceof Auditable&#41; &#123;
    			bpo=&#40;BasePersistentObject&#41;args0;
    			Long oldId=bpo.getId&#40;&#41;;
    			if&#40;oldId!=null&#41;&#123;												
    				BasePersistentObject backupBPO=bpo.getBackupObject&#40;&#41;;
    				backupBPO.setDatabaseStatus&#40;BasePersistentObject.RECORD_UPDATED+"_"+bpo.getBaseRecord&#40;&#41;.getId&#40;&#41;+"_"+&#40;bpo.getDatabaseVersion&#40;&#41;+1&#41;&#41;;
    				systemDAO.saveBackupBPO&#40;backupBPO&#41;;				
    				log.debug&#40;"save advice worked&#58;" + invocation&#41;;
    			&#125;
    			else &#123;
    				//new record
    				bpo.setBaseRecord&#40;bpo&#41;;
    			&#125;
    		&#125;
    		Object rval = invocation.proceed&#40;&#41;;
    		return rval;
    	&#125;
    Here is the BAsePersistentObject from which all my persistent classes inherit from:
    Code:
    public abstract class BasePersistentObject implements Serializable &#123;
    	public static String RECORD_ACTIVE="ACTIVE";
    	public static String RECORD_UPDATED="UPDATED";
    	public static String RECORD_DELETED="DELETED";
    	
        protected Long id;
        protected BasePersistentObject baseRecord;
        protected int databaseVersion;
        protected String databaseStatus=RECORD_ACTIVE;
        protected User createdUser;
        protected Timestamp createdTime;
        protected User lastModifiedUser;
        protected Timestamp lastModifiedTime;
        protected Timestamp systemModifiedTime;
        protected User ownerUser;
            
    // getters, setters omitted
        
        public boolean isActive&#40;&#41; &#123; return getDatabaseStatus&#40;&#41;.equals&#40;"ACTIVE"&#41;; &#125;
    
        public boolean isDeleted&#40;&#41; &#123; return getDatabaseStatus&#40;&#41;.equals&#40;"DELETED"&#41;; &#125;
        
    	public  BasePersistentObject getBackupObject&#40;&#41; &#123;
    		BasePersistentObject bpo=null;
    		try&#123;
    			bpo=&#40;BasePersistentObject&#41;BeanUtils.cloneBean&#40;this&#41;;
    			bpo.setId&#40;null&#41;;
    		&#125;catch&#40;Exception e&#41; &#123;
    			System.out.println&#40;e&#41;;
    		&#125;
    		return bpo;
    	&#125;
    The interesting method here is getBAckupObject(), which returns a copy of this entity for auditing purposes. The classes to be audited will have to implement a marker interface called Auditable.
    Remove advice will simply modify the database status as "DELETED".

    Code:
    public class RemoveDatabaseInterceptor implements MethodInterceptor &#123;
    	private static final Log log = LogFactory.getLog&#40;RemoveDatabaseInterceptor.class&#41;;
    	private SystemDAO systemDAO = null;
    
    	public void setSystemDAO&#40;SystemDAO systemDao&#41; &#123;
            this.systemDAO = systemDao;
        &#125;
    	
    	public Object invoke&#40;MethodInvocation invocation&#41; throws Throwable &#123;
    		log.debug&#40;"remove advice will work&#58;" + invocation&#41;;
    		Object&#91;&#93; args=invocation.getArguments&#40;&#41;;
    		Object args0=args&#91;0&#93;;
    		if&#40;args0 instanceof Auditable&#41; &#123;
    			BasePersistentObject bpo=&#40;BasePersistentObject&#41;args&#91;0&#93;;			
    			if&#40;!bpo.getDatabaseStatus&#40;&#41;.equals&#40;BasePersistentObject.RECORD_ACTIVE&#41;&#41;
    				throw new Exception&#40;"Status of the entity object was not ACTIVE"&#41;;
    			else &#123;
    
    				bpo.setDatabaseStatus&#40;BasePersistentObject.RECORD_DELETED+"_"+bpo.getBaseRecord&#40;&#41;.getId&#40;&#41;&#41;;
    				log.debug&#40;"remove advice worked&#58;" + invocation&#41;;
    			&#125;
    		&#125;
    
    		Object rval = invocation.proceed&#40;&#41;;	
    		return rval;
    		
    	&#125;
    SystemDAO, which handles application wide DAO, looks like:
    Code:
    public interface SystemDAO extends DAO &#123;
    	/**
    	 * When an exception occurs, we want to record it in the database,
    	 * with use of AOP&#40;ExceptionAdvice&#41;. Not to be used directly, the system calls when needed.
    	 * @param ael the ApplicationErrorLog object to be logged in the database.
    	 * @return the ApplicationErrorLog object that was logged in the database.
    	 * @see ExceptionAdvice 
    	 */
        public ApplicationErrorLog saveApplicationErrorLog&#40;ApplicationErrorLog ael&#41;;
        
        /**
    	 * All database create or update operations can use this interface.
    	 * @param bpo the BasePersistentObject to be created or updated in the database.
    	 * Subject to the AOP SaveDatabaseInterceptor if implements Auditable.
    	 * @return the BasePersistentObject that was created or updated in the database.
    	 * @see SaveDatabaseInterceptor
    	 * @see Auditable
    	 */
        public BasePersistentObject saveBPO&#40;BasePersistentObject bpo&#41;;
        
        /**
    	 * Backup records&#40;auditing&#41; are saved through this interface.
    	 * Created to let SaveDatabaseInterceptor bypass this database update.
    	 * @param bpo the BasePersistentObject to be created in the database for auditing purposes.
    	 * @return the BasePersistentObject that was created in the database for auditing purposes..
    	 * @see SaveDatabaseInterceptor
    	 */
        public BasePersistentObject saveBackupBPO&#40;BasePersistentObject bpo&#41;;
        
        /**
    	 * All database "delete" operations use this interface.
    	 * @param bpo the BasePersistentObject to be deleted in the database.
    	 * Subject to the AOP RemoveDatabaseInterceptor if implements Auditable.
    	 * @see RemoveDatabaseInterceptor
    	 * @see Auditable
    	 */
        public void removeBPO&#40;BasePersistentObject bpo&#41;;
        
        /**
    	 * All database "select * from ATABLE where id=?" operations use this interface.
    	 * @param theClass The class name of the entity to be retrieved. 
    	 * @param id The Long representation of the identifier field
    	 * @return the BasePersistentObject that was retrieved from the database.
    	 */
        public BasePersistentObject retrieveBPO&#40;Class theClass,Long id&#41;;
    And the Hibernate implementation:
    Code:
    public class SystemDAOHibernate extends HibernateDaoSupport implements SystemDAO &#123;
        private static final Log log = LogFactory.getLog&#40;SystemDAOHibernate.class&#41;;
    
    	public ApplicationErrorLog saveApplicationErrorLog&#40;ApplicationErrorLog ael&#41; &#123;
    		getHibernateTemplate&#40;&#41;.saveOrUpdate&#40;ael&#41;;
    		return ael;
    	&#125;
    
        public BasePersistentObject saveBPO&#40;BasePersistentObject bpo&#41; &#123;
            getHibernateTemplate&#40;&#41;.saveOrUpdate&#40;bpo&#41;;
            return bpo;
        &#125;
    
        public BasePersistentObject saveBackupBPO&#40;BasePersistentObject bpo&#41; &#123;
            getHibernateTemplate&#40;&#41;.saveOrUpdate&#40;bpo&#41;;
            return bpo;
        &#125;
        
    	public void removeBPO&#40;BasePersistentObject bpo&#41; &#123;
    		getHibernateTemplate&#40;&#41;.saveOrUpdate&#40;bpo&#41;;		
    	&#125;
    
        public BasePersistentObject retrieveBPO&#40;Class theClass,Long id&#41;&#123;
        	return &#40;BasePersistentObject&#41;getHibernateTemplate&#40;&#41;.get&#40;theClass,id&#41;;
        &#125;
    The ExceptionAdvice mentioned above looks like (inserts a record into the APPLICATIONERRORLOG table):

    Code:
    public class ExceptionAdvice implements ThrowsAdvice&#123;
    	private SystemDAO systemDAO = null;
    	private UserDAO userDAO = null;
    	private static final Log log = LogFactory.getLog&#40;ExceptionAdvice.class&#41;;
    	
    	public void setUserDAO&#40;UserDAO userDao&#41; &#123;
            this.userDAO = userDao;
        &#125;
    	public void setSystemDAO&#40;SystemDAO systemDao&#41; &#123;
            this.systemDAO = systemDao;
        &#125;
    
    	public void afterThrowing&#40;Method m,Object&#91;&#93; args,Object target,Exception ex&#41;&#123;
    		log.debug&#40;"Exception advice will work!&#58;"+ex&#41;;
    		ApplicationErrorLog ael=new ApplicationErrorLog&#40;&#41;;
    		Timestamp now = new Timestamp&#40;System.currentTimeMillis&#40;&#41;&#41;;
    		ael.setCreatedTime&#40;now&#41;;
    		
    		ael.setCreatedUser&#40;userDAO.retrieveUserByUserName&#40;"admin"&#41;&#41;;
    		ael.setDescription&#40;"Method&#58;"+m+" Exception&#58;"+ex&#41;;
    		ael.setErrorNumber&#40;"111"&#41;; //TODO&#58; To be implemented by looking at the actual error...		
    		systemDAO.saveApplicationErrorLog&#40;ael&#41;;
    		log.debug&#40;"Exception advice worked!&#58;"+ex&#41;;
    	&#125;
    The database schema for an Auditable class looks like:
    Code:
    create table DEPARTMENT&#40;
    ID NUMERIC NOT NULL primary key,
    DATABASEVERSION NUMERIC NOT NULL,
    BASERECORDID NUMERIC NOT NULL,
    DATABASESTATUS VARCHAR&#40;15&#41; DEFAULT 'ACTIVE' NOT NULL,
    CREATEDUSERID NUMERIC NOT NULL,
    CREATEDTIME TIMESTAMP NOT NULL,
    LASTMODIFIEDUSERID NUMERIC NOT NULL,
    LASTMODIFIEDTIME TIMESTAMP NOT NULL,
    SYSTEMMODIFIEDTIME TIMESTAMP NOT NULL,
    OWNERUSERID NUMERIC NOT NULL,
    NAME VARCHAR&#40;20&#41; NOT NULL,
    DESCRIPTION VARCHAR&#40;100&#41; NOT NULL&#41;;
    And finally the applicationcontext.xml (I know this has been long already )
    Code:
    <beans>
    <!-- BASICDATASOURCE -->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
            <!-- datasource properties omitted -->
        </bean>
    
        <!-- Hibernate SessionFactory -->
        <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
            <property name="dataSource"><ref local="dataSource"/></property>
            <!-- Hibernate definitions omitted -->
        </bean>
    
        <!-- Transaction manager for a single Hibernate SessionFactory &#40;alternative to JTA&#41; -->
        <bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
            <property name="sessionFactory"><ref local="sessionFactory"/></property>
        </bean>
    
    	<bean id="DAOTemplate" lazy-init="true"
    		class="org.springframework.aop.framework.ProxyFactoryBean">
    		<property name="interceptorNames">
    			<list>
    				<value>saveDatabaseAdvisor</value>
    				<value>removeDatabaseAdvisor</value>
    			</list>
    		</property>
    	</bean>
    
        <bean id="userDAO" parent="DAOTemplate" >
    		<property name="proxyInterfaces"><value>dao.UserDAO</value></property>
    		<property name="target">
    			<bean id="userDAOTarget" class="dao.hibernate.UserDAOHibernate"> 
    				<property name="sessionFactory"><ref local="sessionFactory"/></property>
    			</bean> 
    		</property>
        </bean>    
    
        <bean id="systemDAO" parent="DAOTemplate" >
    		<property name="proxyInterfaces"><value>dao.SystemDAO</value></property>
    		<property name="target">
    			<bean id="systemDAOTarget" class="dao.hibernate.SystemDAOHibernate"> 
    				<property name="sessionFactory"><ref local="sessionFactory"/></property>		
    			</bean>	
    		</property>
        </bean>    		
    
    	<bean id="TransactionalFacadeTemplate" lazy-init="true"
    		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    		<property name="transactionManager"><ref local="transactionManager"/></property> 
    		<property name="transactionAttributes"> 
    			<props> 
    				<prop key="update_*">PROPAGATION_REQUIRED</prop> 
    				<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> 
    			</props> 
    		</property>	
    	</bean>
    
     	<bean id="SecureFacadeTemplate" lazy-init="true" parent="TransactionalFacadeTemplate"
    		class="org.springframework.aop.framework.ProxyFactoryBean">
    		<property name="interceptorNames">
    			<list>
    				<value>securityAdvisor</value>
    			</list>
    		</property>
    	</bean>
    	
        <bean id="userManagerFacade" parent="SecureFacadeTemplate" >
    		<property name="proxyInterfaces"><value>service.UserManagerFacade</value></property>
    		<property name="target">
    			<bean id="userManagerFacadeTarget" class="service.impl.UserManagerFacadeImpl"> 
    				<property name="userDAO"><ref local="userDAO"/></property> 
    				<property name="systemDAO"><ref local="systemDAO"/></property> 
    			</bean> 
    		</property>
        </bean>    
    
    	<bean id="saveDatabaseInterceptor" class="util.SaveDatabaseInterceptor">
    		<property name="systemDAO"><ref local="systemDAO"/></property>
    	</bean>
    
    	<bean id="saveDatabaseAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    		<property name="advice"><ref local="saveDatabaseInterceptor"/></property>
    		<property name="patterns">
    			<list>
    				<!--<value>.*save.*</value>-->
    				<value>.*save&#40;?!Backup&#41;\w+</value>		
    			</list>			
    		</property>
    	</bean>
    
    	<bean id="removeDatabaseInterceptor" class="util.RemoveDatabaseInterceptor" >
    		<property name="systemDAO"><ref local="systemDAO"/></property>
    	</bean>
    	
    	<bean id="removeDatabaseAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    		<property name="advice"><ref local="removeDatabaseInterceptor"/></property>
    		<property name="patterns">
    			<list>
    				<value>.*remove.*</value>
    			</list>			
    		</property>
    	</bean>
    
    	<bean id="securityInterceptor" class="util.SecurityInterceptor" />
    
    	<bean id="securityAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    		<property name="advice"><ref local="securityInterceptor"/></property>
    		<property name="patterns">
    			<list>
    				<value>.*retrieve.*</value>
    				<value>.*update_.*</value>
    			</list>			
    		</property>
    	</bean>
    
    	<bean id="exceptionAdvice" class="util.ExceptionAdvice" >
    		<property name="userDAO"><ref local="userDAO"/></property>
    		<property name="systemDAO"><ref local="systemDAO"/></property>
    	</bean>
    
    	<bean id="exceptionAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    		<property name="advice"><ref local="exceptionAdvice"/></property>
    		<property name="patterns">
    			<list>
    				<value>.*</value>
    			</list>			
    		</property>
    	</bean>
    	
    	<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">		
    		<property name="advisorBeanNamePrefix">
    				<value>exceptionAdv</value>			
    		</property>
    		<property name="usePrefix">
    				<value>true</value>			
    		</property>
    	</bean>
    
    </beans>
    And (really finally) for the sake of completeness, here is the SecurityInterceptor:
    Code:
    public class SecurityInterceptor implements MethodInterceptor &#123;
    	private static final Log log = LogFactory.getLog&#40;SecurityInterceptor.class&#41;;
    	
    	public Object invoke&#40;MethodInvocation invocation&#41; throws Throwable &#123;
    //	 Apply crosscutting code
    	doSecurityCheck&#40;invocation&#41;;
    	
    //	 Call next interceptor
    	return invocation.proceed&#40;&#41;;
    	&#125;
    	
    	protected void doSecurityCheck&#40;MethodInvocation invocation&#41; throws UnAuthorizedException &#123;
    		log.debug&#40;"security check performed&#58;"+invocation&#41;; //TODO&#58; implement security check...
    	&#125;
    You can follow the progress of this at http://sourceforge.net/projects/openhelpdesk if you want to.

    Regards,
    Turgay Zengin

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •