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 + -
显示快捷键?