abstractcachableoperator.java
来自「Rapla是一个灵活的多用户资源管理系统。它提供的一些功能有:日历GUI」· Java 代码 · 共 914 行 · 第 1/3 页
JAVA
914 行
/*--------------------------------------------------------------------------*
| Copyright (C) 2006 Christopher Kohlhaas |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by the |
| Free Software Foundation. A copy of the license has been included with |
| these distribution in the COPYING file, if not go to www.fsf.org |
| |
| As a special exception, you are granted the permissions to link this |
| program with every library, which license fulfills the Open Source |
| Definition as published by the Open Source Initiative (OSI). |
*--------------------------------------------------------------------------*/
package org.rapla.storage.impl;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.avalon.framework.logger.Logger;
import org.rapla.components.util.Assert;
import org.rapla.components.util.DateTools;
import org.rapla.components.util.Tools;
import org.rapla.components.xmlbundle.I18nBundle;
import org.rapla.entities.Category;
import org.rapla.entities.DependencyException;
import org.rapla.entities.Entity;
import org.rapla.entities.EntityNotFoundException;
import org.rapla.entities.Named;
import org.rapla.entities.RaplaObject;
import org.rapla.entities.RaplaType;
import org.rapla.entities.UniqueKeyException;
import org.rapla.entities.User;
import org.rapla.entities.configuration.Preferences;
import org.rapla.entities.configuration.internal.PreferencesImpl;
import org.rapla.entities.domain.Allocatable;
import org.rapla.entities.domain.Appointment;
import org.rapla.entities.domain.Permission;
import org.rapla.entities.domain.Reservation;
import org.rapla.entities.dynamictype.Attribute;
import org.rapla.entities.dynamictype.DynamicType;
import org.rapla.entities.dynamictype.DynamicTypeAnnotations;
import org.rapla.entities.internal.ModifiableTimestamp;
import org.rapla.entities.storage.DynamicTypeDependant;
import org.rapla.entities.storage.EntityResolver;
import org.rapla.entities.storage.Mementable;
import org.rapla.entities.storage.RefEntity;
import org.rapla.entities.storage.internal.SimpleEntity;
import org.rapla.framework.RaplaContext;
import org.rapla.framework.RaplaException;
import org.rapla.framework.RaplaLocale;
import org.rapla.storage.CachableStorageOperator;
import org.rapla.storage.IdTable;
import org.rapla.storage.LocalCache;
import org.rapla.storage.RaplaSecurityException;
import org.rapla.storage.ReferenceNotFoundException;
import org.rapla.storage.StorageUpdateListener;
import org.rapla.storage.UpdateEvent;
import org.rapla.storage.UpdateResult;
/** An abstract implementation of the StorageOperator-Interface.
It operates on a LocalCache-Object and doesn't implement
connect, isConnected, refresh, createIdentifier and disconnect.
<b>!!WARNING!!</b> This operator is not thread-safe.
{@link org.rapla.server.internal.ServerServiceImpl} for an example
of an thread-safe wrapper around this storageoperator.
@see LocalCache
*/
public abstract class AbstractCachableOperator
implements CachableStorageOperator
{
private RaplaLocale raplaLocale;
private ArrayList storageUpdateListeners = new ArrayList();
private Object lock = new Object();
private MessageDigest md;
protected LocalCache cache;
/** set encryption if you want to enable password encryption. Possible values
are "sha" or "md5".*/
protected String encryption = "md5";
protected I18nBundle i18n;
protected RaplaContext serviceManager;
Date today;
Logger logger;
protected IdTable idTable = new IdTable();
public AbstractCachableOperator(RaplaContext context) throws RaplaException
{
this.logger = (Logger) context.lookup(Logger.class.getName());
this.serviceManager = context;
raplaLocale = (RaplaLocale) context.lookup(RaplaLocale.ROLE);
i18n = (I18nBundle) context.lookup(I18nBundle.ROLE + "/org.rapla.RaplaResources");
try {
if ( encryption != null )
md = MessageDigest.getInstance( encryption );
} catch ( NoSuchAlgorithmException ex) {
throw new RaplaException ( ex );
}
Assert.notNull(raplaLocale.getLocale());
LocalCache newCache = new LocalCache( raplaLocale.getLocale() );
setCache(newCache);
cache.getSuperCategory().getName().setName(i18n.getLang(), i18n.getString("categories"));
updateToday();
}
protected Logger getLogger() {
return logger;
}
public String getEncryption() {
return encryption;
}
/** returns the current time that is used for storing. The default
implementation returns System.currentTimeMillis(). You can override
it to use another time setting (for example the time on the server).
*/
protected long getCurrentTime() throws RaplaException {
return System.currentTimeMillis();
}
/** this method is called by the update-timer thread once a day.
You need to call it manualy if you changed the system-time that
should be used as base (server/client).
*/
protected void updateToday() {
try {
long currentTime = getCurrentTime();
today = new Date( DateTools.cutDate( currentTime) );
long delay = DateTools.cutDate( currentTime )
+ DateTools.MILLISECONDS_PER_DAY - currentTime ;
TimerTask updateTask = new TimerTask() {
public void run() {
updateToday();
}
};
Timer timer = new Timer( true ); // Start timer as daemon-thread
timer.schedule( updateTask, delay );
} catch (RaplaException ex) {
getLogger().error( "Can't get time. ", ex );
today = new Date( today.getTime() + DateTools.MILLISECONDS_PER_DAY );
}
}
protected I18nBundle getI18n() {
return i18n;
}
// Implentation of StorageOperator
public Entity editObject(Entity o, User user) throws RaplaException {
checkConnected();
if (!(o instanceof RefEntity && o instanceof Mementable))
throw new RaplaException("Can only edit objects implementing the Entity and the Mementable interface.");
Object clone;
try {
RefEntity persistant = resolveId(((RefEntity)o).getId());
clone = ((Mementable)persistant).deepClone();
} catch (EntityNotFoundException ex) {
clone = ((Mementable)o).deepClone();
}
if (clone instanceof ModifiableTimestamp) {
((ModifiableTimestamp)clone).setLastChanged(today);
if ( user != null)
{
((ModifiableTimestamp)clone).setLastChangedBy( user );
}
}
((SimpleEntity)clone).setReadOnly( false );
return (Entity)clone;
}
public void storeAndRemove(final Entity[] storeObjects,final Entity[] removeObjects,final User user) throws RaplaException {
checkConnected();
UpdateEvent evt = new UpdateEvent();
if ( user != null) {
evt.setUserId( ((RefEntity) user).getId() );
}
for (int i = 0; i < storeObjects.length; i++) {
if (!(storeObjects[i] instanceof RaplaObject))
throw new RaplaException("Can only store objects of type " + RaplaObject.class.getName() + ". Class not supported " +storeObjects[i].getClass());
evt.putStore((RefEntity) storeObjects[i]);
}
for (int i = 0; i < removeObjects.length; i++) {
if (!(removeObjects[i] instanceof RaplaObject))
throw new RaplaException("Can only remove objects of type " + RaplaObject.class.getName() +". Class not supported " +removeObjects[i].getClass());
RefEntity entity = (RefEntity) removeObjects[i];
RaplaType type = entity.getRaplaType();
if (Appointment.TYPE.equals( type)
|| Category.TYPE.equals( type )
|| Attribute.TYPE.equals( type )
) {
throw new RaplaException("You can't remove an object of class " + entity.getClass().getName()
+". Please remove it from the parent object and store the parent." );
}
evt.putRemove( entity );
}
dispatch ( evt );
}
public Collection getObjects(final RaplaType raplaType) throws RaplaException {
checkConnected();
return cache.getCollection(raplaType);
}
public List getVisibleEntities(final User user) throws RaplaException {
checkConnected();
ArrayList list = new ArrayList();
Iterator it = cache.getVisibleEntities();
while (it.hasNext())
list.add(it.next());
return list;
}
public User getUser(final String username) throws RaplaException {
checkConnected();
return cache.getUser(username);
}
public Preferences getPreferences(final User user) throws RaplaException {
checkConnected();
// Test if user is already stored
if ( user != null ) {
resolveId( ((RefEntity) user).getId());
}
Preferences pref = cache.getPreferences(user);
if (pref == null) {
PreferencesImpl newPref = new PreferencesImpl();
newPref.setOwner( user );
newPref.setId(createIdentifier( Preferences.TYPE));
pref = newPref;
cache.put( newPref );
}
return pref;
}
public SortedSet getAppointments(final User user,final Date start,final Date end) throws RaplaException {
checkConnected();
return cache.getAppointments(user,start,end);
}
public List getReservations(final User user,final Date start,final Date end) throws RaplaException {
return cache.getReservations(user,start,end);
}
public Category getSuperCategory() {
return cache.getSuperCategory();
}
public void addStorageUpdateListener(StorageUpdateListener listener) {
storageUpdateListeners.add(listener);
}
public void removeStorageUpdateListener(StorageUpdateListener listener) {
storageUpdateListeners.remove(listener);
}
public StorageUpdateListener[] getStorageUpdateListeners() {
return (StorageUpdateListener[])storageUpdateListeners.toArray(new StorageUpdateListener[]{});
}
protected void fireStorageUpdated(final UpdateResult evt) {
StorageUpdateListener[] listeners = getStorageUpdateListeners();
for (int i = 0;i<listeners.length; i++) {
listeners[i].objectsUpdated(evt);
}
}
protected void fireUpdateError(final RaplaException ex) {
if (storageUpdateListeners.size() == 0)
return;
StorageUpdateListener[] listeners = getStorageUpdateListeners();
for (int i = 0;i<listeners.length; i++) {
listeners[i].updateError(ex);
}
}
protected void fireStorageDisconnected() {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?