📄 facadeimpl.java
字号:
/*--------------------------------------------------------------------------*
| 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.facade.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeSet;
import java.util.Vector;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.rapla.components.util.Command;
import org.rapla.components.util.CommandQueue;
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.Entity;
import org.rapla.entities.EntityNotFoundException;
import org.rapla.entities.Ownable;
import org.rapla.entities.RaplaObject;
import org.rapla.entities.RaplaType;
import org.rapla.entities.User;
import org.rapla.entities.UserComparator;
import org.rapla.entities.configuration.CalendarModelConfiguration;
import org.rapla.entities.configuration.Preferences;
import org.rapla.entities.configuration.RaplaMap;
import org.rapla.entities.configuration.internal.CalendarModelConfigurationImpl;
import org.rapla.entities.configuration.internal.RaplaMapImpl;
import org.rapla.entities.domain.Allocatable;
import org.rapla.entities.domain.Appointment;
import org.rapla.entities.domain.Period;
import org.rapla.entities.domain.Permission;
import org.rapla.entities.domain.Reservation;
import org.rapla.entities.domain.internal.AllocatableImpl;
import org.rapla.entities.domain.internal.AppointmentImpl;
import org.rapla.entities.domain.internal.PeriodImpl;
import org.rapla.entities.domain.internal.ReservationImpl;
import org.rapla.entities.dynamictype.Attribute;
import org.rapla.entities.dynamictype.AttributeType;
import org.rapla.entities.dynamictype.Classifiable;
import org.rapla.entities.dynamictype.Classification;
import org.rapla.entities.dynamictype.ClassificationFilter;
import org.rapla.entities.dynamictype.DynamicType;
import org.rapla.entities.dynamictype.DynamicTypeAnnotations;
import org.rapla.entities.dynamictype.internal.AttributeImpl;
import org.rapla.entities.dynamictype.internal.DynamicTypeImpl;
import org.rapla.entities.internal.CategoryImpl;
import org.rapla.entities.internal.UserImpl;
import org.rapla.entities.storage.Mementable;
import org.rapla.entities.storage.RefEntity;
import org.rapla.facade.AllocationChangeEvent;
import org.rapla.facade.AllocationChangeListener;
import org.rapla.facade.ClientFacade;
import org.rapla.facade.Conflict;
import org.rapla.facade.ModificationEvent;
import org.rapla.facade.ModificationListener;
import org.rapla.facade.PeriodModel;
import org.rapla.facade.UpdateErrorListener;
import org.rapla.facade.UpdateModule;
import org.rapla.framework.RaplaContext;
import org.rapla.framework.RaplaContextException;
import org.rapla.framework.RaplaException;
import org.rapla.framework.RaplaLocale;
import org.rapla.storage.CachableStorageOperator;
import org.rapla.storage.RaplaSecurityException;
import org.rapla.storage.StorageOperator;
import org.rapla.storage.StorageUpdateListener;
import org.rapla.storage.UpdateResult;
/** This is the default implementation of the necessary Client-Facade to the DB-Subsystem.
* <p>Sample configuration 1:
<pre>
<facade id="facade">
<store>file</store>
</facade>
</pre>
</p>
<p>Sample Configuration 2:
<pre>
<facade id="facade" logger="facade">
<store>remote</store>
<username>homer</username>
<password>duffs</password>
</facade>
</pre>
This facade automatically starts with user homer.
* </p>
* <p>The store entry contains the id of a storage-component.
* Storage-Components are all components that implement the
* {@link StorageOperator} interface.
* </p>
*/
public class FacadeImpl extends AbstractLogEnabled
implements
ClientFacade
,StorageUpdateListener
{
protected CommandQueue notifyQueue;
private Configuration operatorConfig;
private User workingUser = null;
private User originalUser = null;
private StorageOperator operator;
private Vector modificatonListenerList = new Vector();
private Vector allocationListenerList = new Vector();
private Vector errorListenerList = new Vector();
private I18nBundle i18n;
private PeriodModelImpl periodModel;
private ConflictFinder conflictFinder;
String username;
String password;
Locale locale;
public FacadeImpl(RaplaContext context,Configuration config, Logger logger) throws RaplaException
{
enableLogging( logger );
i18n = (I18nBundle) context.lookup(I18nBundle.ROLE + "/org.rapla.RaplaResources");
locale = ((RaplaLocale)context.lookup(RaplaLocale.ROLE)).getLocale();
operatorConfig = config.getChild("store");
getLogger().debug("Facade configured with operator '" + operatorConfig.getValue("*") + "'");
username = config.getChild("username").getValue(null);
password = config.getChild("password").getValue("");
try {
operator = (StorageOperator) context.lookup(StorageOperator.ROLE + "/" + operatorConfig.getValue("*"));
conflictFinder = new ConflictFinder( operator );
operator.addStorageUpdateListener(this);
}
catch (RaplaContextException ex)
{
throw new RaplaContextException
(
CachableStorageOperator.ROLE,
"Store at " + operatorConfig.getLocation()
+ " is not found (or could not be initialized)"
,ex
);
}
notifyQueue = org.rapla.components.util.CommandQueue.createCommandQueue();
if (username!=null)
if (!login(username,password.toCharArray()))
throw new RaplaException(i18n.getString("error.login"));
initRefresh();
}
//Implementation of StorageUpdateListener.
/** This method is called by the storage-operator, when stored objects
have changed.
<strong>Caution:</strong> You must not lock the storage operator during processing
of this call, because it could have been locked by the store method, causing deadlocks
*/
public void objectsUpdated(UpdateResult evt) {
if (getLogger().isDebugEnabled())
getLogger().debug("Objects updated");
notifyQueue.enqueue(new UserCheckCommand());
fireUpdateEvent( evt );
}
public void switchTo(User user) {
if (user == null) {
workingUser = originalUser;
originalUser = null;
} else {
originalUser = workingUser;
workingUser = user;
}
// fireUpdateEvent(new ModificationEvent());
}
public boolean canSwitchBack() {
return originalUser != null;
}
public void updateError(RaplaException ex) {
getLogger().fatalError(ex.getMessage(),ex);
fireUpdateError(ex);
}
public void storageDisconnected() {
fireStorageDisconnected();
}
/******************************
* Update-module *
******************************/
public boolean isClientForServer() {
return operator.supportsActiveMonitoring();
}
public void refresh() throws RaplaException {
synchronized (operator.getLock()) {
if ( operator.supportsActiveMonitoring())
{
operator.refresh();
}
}
}
public void addModificationListener(ModificationListener listener) {
modificatonListenerList.add(listener);
}
public void removeModificationListener(ModificationListener listener) {
modificatonListenerList.remove(listener);
}
public ModificationListener[] getModificationListeners() {
return (ModificationListener[])modificatonListenerList.toArray(new ModificationListener[]{});
}
private Collection getModificationListeners(boolean invokeLater) {
if (modificatonListenerList.size() == 0)
return Tools.EMPTY_LIST;
synchronized (this) {
Collection list = new ArrayList(3);
if ( periodModel != null) {
list.add( periodModel );
}
Iterator it = modificatonListenerList.iterator();
while (it.hasNext()) {
ModificationListener listener = (ModificationListener) it.next();
if (listener.isInvokedOnAWTEventQueue() == invokeLater)
list.add(listener);
}
return list;
}
}
public void addAllocationChangedListener(AllocationChangeListener listener) {
allocationListenerList.add(listener);
}
public void removeAllocationChangedListener(AllocationChangeListener listener) {
allocationListenerList.remove(listener);
}
private Collection getAllocationChangeListeners(boolean invokeLater) {
if (allocationListenerList.size() == 0)
return Tools.EMPTY_LIST;
synchronized (this) {
Collection list = new ArrayList(3);
Iterator it = allocationListenerList.iterator();
while (it.hasNext()) {
AllocationChangeListener listener = (AllocationChangeListener) it.next();
if (listener.isInvokedOnAWTEventQueue() == invokeLater)
list.add(listener);
}
return list;
}
}
public void addUpdateErrorListener(UpdateErrorListener listener) {
errorListenerList.add(listener);
}
public void removeUpdateErrorListener(UpdateErrorListener listener) {
errorListenerList.remove(listener);
}
public UpdateErrorListener[] getUpdateErrorListeners() {
return (UpdateErrorListener[])errorListenerList.toArray(new UpdateErrorListener[]{});
}
protected void fireUpdateError(RaplaException ex) {
UpdateErrorListener[] listeners = getUpdateErrorListeners();
for (int i = 0;i<listeners.length; i++) {
listeners[i].updateError(ex);
}
}
protected void fireStorageDisconnected() {
UpdateErrorListener[] listeners = getUpdateErrorListeners();
for (int i = 0;i<listeners.length; i++) {
listeners[i].disconnected();
}
}
final class UserCheckCommand implements Command {
public void execute() {
try {
if (workingUser == null)
return;
synchronized (operator.getLock()) {
Iterator it = operator.getObjects(User.TYPE).iterator();
while (it.hasNext()) {
User user = (User)it.next();
if (user.equals(workingUser))
{
workingUser = user;
return;
}
}
}
if (workingUser == null)
return;
throw new EntityNotFoundException("User (" + workingUser + ") not found");
} catch (RaplaException ex) {
fireUpdateError(ex);
}
}
}
private final void initRefresh()
{
TimerTask refreshTask = new TimerTask() {
public void run() {
initRefresh();
}
};
synchronized (operator.getLock())
{
Timer timer = new Timer( true ); // Start timer as daemon-thread
int delay = 30000;
if ( operator.isConnected())
{
try
{
delay = operator.getPreferences( null).getEntryAsInteger(UpdateModule.REFRESH_INTERVAL_ENTRY, delay);
refresh();
}
catch (RaplaException e)
{
getLogger().error("Error refreshing.", e);
}
}
timer.schedule( refreshTask, delay );
}
}
final class UpdateCommand implements Runnable,Command {
Collection listeners;
boolean bError = false;
ModificationEvent modificationEvent;
AllocationChangeEvent[] allocationChangeEvents;
public UpdateCommand(Collection modificationListeners,Collection allocationChangeListeners,UpdateResult evt) {
this.listeners = new ArrayList(modificationListeners);
this.listeners.addAll( allocationChangeListeners );
if ( evt != null )
{
Set storeEvents = new HashSet();
storeEvents.addAll( evt.getChangeObjects());
storeEvents.addAll( evt.getAddObjects());
Set removeEvents = evt.getRemoveObjects();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -