[DS-247] [DS-243] [DSB-37] Extraction of complete DSpace 2.0 Kernel, RequestService, SessionService, EventService and CachingServices.

git-svn-id: http://scm.dspace.org/svn/repo/modules/dspace-services/trunk@4100 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
Mark Diggory
2009-07-22 23:54:41 +00:00
parent c77edcd384
commit af425e130d
104 changed files with 13243 additions and 319 deletions

76
api/pom.xml Normal file
View File

@@ -0,0 +1,76 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dspace</groupId>
<artifactId>dspace-services-api</artifactId>
<name>DSpace Core API</name>
<description>The core services API for DSpace</description>
<url>http://projects.dspace.org</url>
<inceptionYear>Monday, September 1, 2008</inceptionYear>
<organization>
<name>The DSpace Foundation</name>
<url>http://www.dspace.org</url>
</organization>
<packaging>jar</packaging>
<parent>
<artifactId>dspace-services</artifactId>
<groupId>org.dspace</groupId>
<version>2.0.0-SNAPSHOT</version><!--dspace2.version-->
</parent>
<!--
The Subversion repository location is used by Continuum to
update against when changes have occured, this spawns a new
build cycle and releases snapshots into the snapshot repository
below.
-->
<scm>
<connection>scm:svn:http://scm.dspace.org/svn/repo/modules/dspace-services/trunk/api</connection>
<developerConnection>scm:svn:https://scm.dspace.org/svn/repo/modules/dspace-services/trunk/api</developerConnection>
<url>http://scm.dspace.org/svn/repo/modules/dspace-services/trunk/api</url>
</scm>
<repositories>
<repository>
<id>dspace-snapshot</id>
<name>DSpace Snapshot Repository</name>
<url>http://maven.dspace.org/snapshot</url>
<releases>
<enabled>false</enabled>
<checksumPolicy>fail</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
</repository>
</repositories>
<dependencies>
<!-- should be an absolutely minimal set of dependencies -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<!-- include the readme.txt file and the java source files -->
<resource>
<directory>${basedir}/src/main/java</directory>
<includes>
<include>**/*.java</include>
<include>**/*.html</include>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>

View File

@@ -0,0 +1,74 @@
/**
* $Id: Activator.java 3492 2009-02-24 16:03:56Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/kernel/Activator.java $
* Activator.java - DS2 - Feb 24, 2009 11:44:14 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.kernel;
/**
* An activator is a special type which allows a provider to be plugged into the system by dropping a jar file
* in with the kernel and adding in a hook in the configuration file. Activators are started after the
* initial classes and the service manager have already been started. All classes which implement this
* must have: <br/>
* 1) A public empty constructor (takes no parameters) (e.g. public MyClass() {} ) <br/>
* <br/>
* If you want the system to execute your class then you must list it in the config file with the fully qualified classpath
* (NOTE that the xxx can be anything as long as it is unique): <br/>
* <b>activator.xxx = org.dspace.MyClass</b> <br/>
* <br/>
* {@link #start(ServiceManager)} will be called after the class is created during kernel startup.
* Developers should create their providers/plugins/etc. in this method and
* use the registration methods in the {@link ServiceManager} to register them.
* {@link #stop(ServiceManager)} will be called when the kernel shuts down. Perform any cleanup/shutdown actions
* you like during this phase (unregistering your services here is a good idea). <br/>
* <br/>
* This is modeled after the OSGi BundleActivator <br/>
* <br/>
* There is another type of activator used in DSpace but it is configured via the configuration service only.
* The class activator is configured by creating a config property like this
* (NOTE that the xxx can be anything as long as it is unique): <br/>
* <b>activator.class.xxx = org.dspace.MyClass;org.dspace.MyServiceName;constructor</b> <br/>
* Unlike the normal activators, these are started up when the kernel core services start and thus can actually
* be accessed from the service manager and referenced in providers and plugins.
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface Activator {
/**
* This is called when the service manager is starting this activator, it is only called once.
* It will be called after the core services are started. The ClassLoader used will be the one
* that this class is associated with to ensure all dependencies are available. <br/>
* This method should be used to startup and register services in most cases but it can be used
* to simply perform some system startup actions if desired. <br/>
* Exceptions thrown out of this method will not cause the system startup to fail. <br/>
*
* @param serviceManager the current system service manager
*/
public void start(ServiceManager serviceManager);
/**
* This is called when the service manager is shutting down this activator, it is only called once.
* It will be called before the core services are stopped. The ClassLoader used will be the one
* that this class is associated with to ensure all dependencies are available. <br/>
* This method should be used to shutdown and unregister services in most cases but it can be used
* to simply perform some system shutdown actions if desired. <br/>
* Exceptions thrown out of this method will not cause the system shutdown to fail. <br/>
* WARNING: this can hang the shutdown by performing operations that take a long long time or are deadlocked,
* the developer is expected to ensure this does not happen
*
* @param serviceManager the current system service manager
*/
public void stop(ServiceManager serviceManager);
}

View File

@@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.dspace.kernel;
/**
* Beans that have a lifecycle and can be controlled via their lifecycle implement this interface.
* Based on the Sakai K2 lifecycle interface -AZ
*
* @param <T> the type of object managed by this lifecycle.
*/
public interface CommonLifecycle<T> {
/**
* Starts the bean. This initializes and causes the object to begin functioning.
* Should not happen automatically when the object is created.
*/
public void start();
/**
* Stops the bean. This turns the object off and causes related things to be shutdown.
* Object should be able to be started again.
*/
public void stop();
/**
* Gets a reference to the bean that is being managed inside this lifecycle.
* @return the managed object
*/
public T getManagedBean();
/**
* Destroy the managed bean entirely. It will be stopped first if not stopped and cannot be
* started again afterwards.
*/
public void destroy();
}

View File

@@ -0,0 +1,52 @@
/**
* $Id: DSpaceKernel.java 3221 2008-10-21 16:19:57Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/kernel/DSpaceKernel.java $
* DSpaceKernel.java - DSpace2 - Oct 6, 2008 2:22:36 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.kernel;
import org.dspace.services.ConfigurationService;
/**
* The interface of the Kernel,
* this is the most core piece of the system and initalizing this will startup the dspace core
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface DSpaceKernel {
public static final String KERNEL_NAME = "Kernel";
public static final String MBEAN_PREFIX = "org.dspace:name=";
public static final String MBEAN_SUFFIX = ",type=DSpaceKernel";
public static final String MBEAN_NAME = MBEAN_PREFIX+KERNEL_NAME+MBEAN_SUFFIX;
/**
* @return the unique MBean name of this DSpace Kernel
*/
public String getMBeanName();
/**
* @return true if this Kernel is started and running
*/
public boolean isRunning();
/**
* @return the DSpace service manager instance for this Kernel
*/
public ServiceManager getServiceManager();
/**
* @return the DSpace configuration service for this Kernel
*/
public ConfigurationService getConfigurationService();
}

View File

@@ -0,0 +1,106 @@
/**
* $Id: DSpaceKernelManager.java 3433 2009-02-04 10:16:39Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/kernel/DSpaceKernelManager.java $
* DSpaceKernelManager.java - DSpace2 - Oct 6, 2008 2:35:01 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.kernel;
import java.lang.management.ManagementFactory;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
/**
* Allows the DSpace kernel to be accessed if desired
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceKernelManager {
/**
* The current kernel.
*/
private DSpaceKernel kernel;
/**
* A lock on the kernel to handle multiple threads getting the first item.
*/
private Object lock = new Object();
/**
* Get the kernel, this will be a single instance for the JVM, but the method will retrieve
* the same instance regardless of this object instance.
*
* @return the DSpace kernel
* @throws IllegalStateException if the kernel is not available
*/
public DSpaceKernel getKernel() {
return getKernel(null);
}
/**
* Get the kernel, this will be a single instance for the JVM, but the method will retrieve
* the same instance regardless of this object instance.
*
* @param name this is the name of this kernel instance, if you do not know what this is then use null
* @return the DSpace kernel
* @throws IllegalStateException if the kernel is not available or not running
*/
public DSpaceKernel getKernel(String name) {
if (kernel == null) {
name = checkName(name);
synchronized (lock) {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try {
ObjectName kernelName = new ObjectName(name);
kernel = (DSpaceKernel) mbs.invoke(kernelName, "getManagedBean", null, null);
if (! kernel.isRunning()) {
throw new IllegalStateException("The DSpace kernel is not started yet, please start it before attempting to use it");
}
} catch (InstanceNotFoundException e) {
throw new IllegalStateException(e);
} catch (MBeanException e) {
throw new IllegalStateException(e);
} catch (ReflectionException e) {
throw new IllegalStateException(e);
} catch (MalformedObjectNameException e) {
throw new IllegalStateException(e);
} catch (NullPointerException e) {
throw new IllegalStateException(e);
}
}
}
return kernel;
}
/**
* @param name the name for the kernel
* @return a proper mbean name based on the given name
*/
public static String checkName(String name) {
String mbeanName = name;
if (name == null || "".equals(name)) {
mbeanName = DSpaceKernel.MBEAN_NAME;
} else {
if (! name.startsWith(DSpaceKernel.MBEAN_PREFIX)) {
mbeanName = DSpaceKernel.MBEAN_PREFIX + name + DSpaceKernel.MBEAN_SUFFIX;
}
}
return mbeanName;
}
}

View File

@@ -0,0 +1,59 @@
/**
* $Id: ConfigChangeListener.java 3229 2008-10-23 13:13:58Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/kernel/mixins/ConfigChangeListener.java $
* ConfigChangeListener.java - DSpace2 - Oct 20, 2008 11:38:44 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.kernel.mixins;
import java.util.List;
import java.util.Map;
/**
* DSpace Service/Provider mixin:
* Allows a service to be notified when a configuration change occurs,
* this is primarily useful for when someone wants to make a configuration change when
* the system is already running without requiring a restart <br/>
* This is a DSpace mixin which means it will be triggered because this is a DSpace service or provider,
* the system will pick up on the fact that the java bean is implementing this interface and will
* take the appropriate actions, there is no need to register this listener
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface ConfigChangeListener {
/**
* Allows the listener to filter the change notifications so it is only notified when
* the named configuration items change, for example: <br/>
* If this method returns an array with "upload.enabled" then whenever this configuration setting changes
* the listener will be called. If any other settings change the listener will not be called
* unless they are specific bean properties for this service (e.g. downloadEnabled@org.dspace.ThisService).
* If you want to be notified when any configuration setting changes then simply return a null
* or an empty string and the listener will be called for every configuration update.
*
* @return an array of configuration string names (e.g. {"system.name","upload.enabled"})
* OR null/empty to be notified for every configuration setting that changes
*/
public String[] notifyForConfigNames();
/**
* This listener method will be called whenever the configuration settings change (depending on the filter),
* this will only be called once for each config update regardless of the number of settings that were actually changed <br/>
* NOTE: This will strip off the beanName from any service property settings,
* Example: downloadEnabled@org.dspace.ThisService => downloadEnabled <br/>
*
* @param changedSettingNames includes the names of all settings that changed
* @param changedSettings includes the map of all settings that changed
*/
public void configurationChanged(List<String> changedSettingNames, Map<String, String> changedSettings);
}

View File

@@ -0,0 +1,31 @@
/**
* $Id: InitializedService.java 3229 2008-10-23 13:13:58Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/kernel/mixins/InitializedService.java $
* InitializingService.java - DSpace2 - Oct 23, 2008 12:00:01 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.kernel.mixins;
/**
* This service mixin will cause the service/provider/etc. to be initialized when it is started by the service
* manager, after all injections are complete the init method will be called,
* any initialization that a service needs to do should happen here
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface InitializedService {
/**
* Executed after the service is created and has had all dependencies and configurations injected
*/
public void init();
}

View File

@@ -0,0 +1,37 @@
/**
* $Id: OrderedService.java 3236 2008-10-24 16:46:39Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/kernel/mixins/OrderedService.java $
* OrderedService.java - DSpace2 - Oct 24, 2008 4:54:26 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.kernel.mixins;
/**
* This service mixin will cause the service/provider/etc. to be ordered against other
* classes that implement the same interface (not this one),
* classes that do not implement this interface
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface OrderedService {
/**
* Sets the order to load the bean which implements this method compared
* to other beans of the same type, lower orders (numbers) will be loaded first
* (i.e. order 1 will appear before order 3 in the list) and the
* orders do not have to be consecutive (there can be gaps),
* 2 beans with the same order or beans with no order set will be ordered randomly
* @return an int which represents the loading order
*/
public int getOrder();
}

View File

@@ -0,0 +1,62 @@
/**
* $Id: ServiceChangeListener.java 3242 2008-10-27 16:07:03Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/kernel/mixins/ServiceChangeListener.java $
* ServiceChangeListener.java - DSpace2 - Oct 24, 2008 6:39:29 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.kernel.mixins;
import java.util.List;
/**
* This service manager mixin will allow a service to be notified when other services change,
* this is useful for keeping an eye on changing providers, filters, and other services which
* drop in and out
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface ServiceChangeListener {
/**
* Allows filtering so that notifications are only sent when classes implement
* or are of one of the types specified, the listener method will only
* be called once regardless of how many types match <br/>
* Just return null or empty array to be notified for all service registrations
*
* @return an array of classes OR null to be notified of all service registrations
*/
public Class<?>[] notifyForTypes();
/**
* This will be called when services are newly registered with the service manager
* (will not be called when the core services are starting up though) <br/>
* It is not called until the service is fully initialized and
* is called once and only once per service that is registered <br/>
*
* @param serviceName the name of the service
* @param service the service bean
* @param implementedTypes a list of all the class types which this service implements
*/
public void serviceRegistered(String serviceName, Object service, List<Class<?>> implementedTypes);
/**
* This will be called when services are removed from the service manager,
* services which are replaced will not have this method called and will only call
* {@link #serviceRegistered(String, Object, List)} <br/>
* It is called immediately before the service is completely destroyed
* so that the service object is still valid <br/>
*
* @param serviceName the name of the service
* @param service the service bean
*/
public void serviceUnregistered(String serviceName, Object service);
}

View File

@@ -0,0 +1,38 @@
/**
* $Id: ServiceManagerReadyAware.java 3497 2009-02-25 17:39:08Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/kernel/mixins/ServiceManagerReadyAware.java $
* ServiceManagerReadyAware.java - DS2 - Feb 25, 2009 11:41:35 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.kernel.mixins;
import org.dspace.kernel.ServiceManager;
/**
* This service manager mixin will cause a service to be notified when the servicemanager has started
* up all known services (including activators), this is useful if a service wants to do lookups
* of all known services or providers of a certain type when the system startup is complete,
* it can also be used as a way to execute some code when the service manager startup is complete
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface ServiceManagerReadyAware {
/**
* This is called when the startup of all core services and activators is complete <br/>
* WARNING: This will never be called for providers which are registered with a servicemanager
* which is already running!
*
* @param serviceManager the completely started service manager
*/
public void serviceManagerReady(ServiceManager serviceManager);
}

View File

@@ -0,0 +1,32 @@
/**
* $Id: ShutdownService.java 3229 2008-10-23 13:13:58Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/kernel/mixins/ShutdownService.java $
* DestroyedService.java - DSpace2 - Oct 23, 2008 12:03:43 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.kernel.mixins;
/**
* This service mixin will cause the service/provider/etc. to be shutdown when the service manager is shutting down the service,
* this will typically be called when the kernel is stopped or destroyed,
* any cleanup that a service needs to do when it is shutdown should happen here
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface ShutdownService {
/**
* Called as the service manager is stopping or shutting down
*/
public void shutdown();
}

View File

@@ -0,0 +1,87 @@
/*
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/providers/CacheProvider.java $
*
* $Revision: 3236 $
*
* $Date: 2008-10-24 09:46:39 -0700 (Fri, 24 Oct 2008) $
*
* Copyright (c) 2008, The DSpace Foundation. 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 DSpace Foundation 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
* HOLDERS 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.
*/
package org.dspace.providers;
import java.util.List;
import org.dspace.services.model.Cache;
import org.dspace.services.model.CacheConfig;
/**
* This is a provider (pluggable functionality) for DSpace<br/>
* This allows an external system to define how caches are handled in DSpace by implementing this interface
* and registering it with the service manager<br/>
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface CacheProvider {
/**
* Gets all the caches that this provider knows about
*
* @return a list of all the caches which the caching service knows about
*/
public List<Cache> getCaches();
/**
* Construct a {@link Cache} with the given name (must be unique) OR retrieve the one
* that already exists with this name <br/>
* NOTE: providers will never be asked to provide request caches (e.g. {@link CacheConfig.CacheScope#REQUEST})
*
* @param cacheName the unique name for this cache (e.g. org.dspace.user.UserCache)
* @param config (optional) a configuration object, the cache should adhere to the settings in it,
* if it is null then just use defaults
* @return a cache which can be used to store serializable objects
* @throws IllegalArgumentException if the cache name is already in use or the config is invalid
*/
public Cache getCache(String cacheName, CacheConfig config);
/**
* Flush and destroy the cache with this name,
* if the cache does not exist then this does nothing (should not fail if the cache does not exist)
* @param cacheName the unique name for this cache (e.g. org.dspace.user.UserCache)
*/
public void destroyCache(String cacheName);
/**
* Clears the contents of all caches managed by this provider
*/
public void resetCaches();
}

View File

@@ -0,0 +1,144 @@
/*
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/services/CachingService.java $
*
* $Revision: 3253 $
*
* $Date: 2008-10-30 05:02:18 -0700 (Thu, 30 Oct 2008) $
*
* Copyright (c) 2008, The DSpace Foundation. 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 DSpace Foundation 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
* HOLDERS 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.
*/
package org.dspace.services;
import java.util.List;
import org.dspace.services.model.Cache;
import org.dspace.services.model.CacheConfig;
/**
* A service to manage creation and retrieval of caches
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface CachingService {
/**
* This is the cache key used to stored requests in a request cache,
* typically handled by a servlet filter but can be handled by anything,
* this is here to ensure we use the right name
*/
public static final String REQUEST_CACHE = "dsRequestCache";
/**
* This is the key in the request cache which holds the current http request (if there is one)
*/
public static final String HTTP_REQUEST_KEY = "httpRequest";
/**
* This is the key in the request cache which holds the current http response (if there is one)
*/
public static final String HTTP_RESPONSE_KEY = "httpResponse";
/**
* This is the key in the request cache which holds the current request
*/
public static final String REQUEST_KEY = "request";
/**
* This is the key in the request cache which holds the current response
*/
public static final String RESPONSE_KEY = "response";
/**
* This is the key in the request cache which holds the current locale
*/
public static final String LOCALE_KEY = "locale";
/**
* This is the key in the request cache which holds the current session ID
*/
public static final String SESSION_ID_KEY = "session";
/**
* This is the key in the request cache which holds the current request ID
*/
public static final String REQUEST_ID_KEY = "requestId";
/**
* Gets all the caches that the service knows about,
* this will include caches of all scopes but only includes request caches for the current thread
*
* @return a list of all the caches which the caching service knows about
*/
public List<Cache> getCaches();
/**
* Construct a Cache with the given name (often this is the fully qualified classpath of the api
* for the service that is being cached or the class if there is no api) OR retrieve the one
* that already exists with this name,
* this will operate on system defaults (probably a distributed cache without replication) OR
* it will use the defaults which are configured for this cacheName (part of the underlying implementation)
* if the cacheConfig is null <br/>
* This can only retrieve request caches for the current request <br/>
* If the cache already exists then the cacheConfig is ignored <br/>
*
* @param cacheName the unique name for this cache (e.g. org.dspace.user.UserCache)
* @param cacheConfig defines the configuration for this cache
* @return a cache which can be used to store objects
*/
public Cache getCache(String cacheName, CacheConfig cacheConfig);
/**
* Flushes and destroys the cache with this name,
* generally there is no reason to call this
*
* @param cacheName the unique name for this cache (e.g. org.dspace.user.UserCache)
*/
public void destroyCache(String cacheName);
/**
* Get a status report of cache usage which is suitable for log or screen output
*
* @param cacheName (optional) the unique name for this cache (e.g. org.dspace.user.UserCache)
* OR null for status of all caches
* @return a string representing the current status of the specified cache or all caches
*/
public String getStatus(String cacheName);
/**
* Clears all caches,
* generally there is no reason to call this
*
* @throws SecurityException if the current user does not have super user permissions
*/
public void resetCaches();
/**
* Unbinds all request caches, destroys the caches completely,
* you should not call this unless you know what you are doing,
* it is handled automatically by the system
*/
public void unbindRequestCaches();
}

View File

@@ -0,0 +1,72 @@
/**
* $Id: RequestService.java 3285 2008-11-13 18:30:54Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/services/RequestService.java $
* RequestService.java - DSpace2 - Oct 14, 2008 4:59:22 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services;
import org.dspace.services.model.RequestInterceptor;
/**
* Allows for the managing of requests in the system in a way which is independent
* from any underlying system or code
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface RequestService {
/**
* Initiates a request in the system,
* normally this would be triggered by a servlet request starting <br/>
* Only one request can be associated with the current thread so if another one is running it will be
* destroyed and a new one will be created <br/>
* Note that requests are expected to be manually ended somehow and will not be closed out automatically
*
* @return the unique generated id for the new request
* @throws IllegalArgumentException if the session is null, invalid, or there is no current session
*/
public String startRequest();
/**
* Ends the current running request, this can indicate success or failure of the request,
* this will trigger the interceptors and normally would be caused by a servlet request ending,
* note that a request cannot be ended twice, once it is ended this will just return null
*
* @param failure (optional) this is the exception associated with the failure,
* leave as null if the request is ending successfully (you can make up a {@link RuntimeException}
* if you just need to indicate that the request failed)
* @return the request ID if the request closes successfully and is not already closed OR null if there is no current request
*/
public String endRequest(Exception failure);
/**
* Finds out of there is a request running in this thread and if so what the id of that request is
*
* @return the id of the current request for this thread OR null if there is not one
*/
public String getCurrentRequestId();
/**
* Allows developers to perform actions on the start and end of the request cycle,
* if you decide you do not need to use your interceptor anymore then simply destroy
* it (dereference it) and the service will stop calling it,
* along those lines you should
* not register an interceptor that you do not keep a reference to (like an inline class
* or registerRequestListener(new YourInterceptor())) as this will be destroyed immediately,
* this registration is ClassLoader safe
*
* @param interceptor an implementation of {@link RequestInterceptor}
* @throws IllegalArgumentException if this priority is invalid or the input is null
*/
public void registerRequestInterceptor(RequestInterceptor interceptor);
}

View File

@@ -0,0 +1,97 @@
/**
* $Id: SessionService.java 3406 2009-01-30 10:57:39Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/services/SessionService.java $
* SessionService.java - DSpace2 - Oct 14, 2008 11:44:57 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services;
import java.util.List;
import org.dspace.services.model.Session;
/**
* Provides access to user sessions and allows for initializing user sessions
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface SessionService {
/**
* Start a new session and destroy any existing session that is known for this thread,
* will bind this to the current request and capture all required session information <br/>
* WARNING: there is normally no need to call this method as the session is created
* for you when using webapps, this is only needed when there is a requirement to
* create a session (operating outside a servlet container or manually handling sessions)
*
* @param sessionId (optional) if null this is generated automatically,
* otherwise the given session ID will be used if it is not already taken or assigned
* @return the session object
*/
public Session startSession(String sessionId);
/**
* Bind the session for the given user (or anonymous),
* this is useful for associating an authenticated user with a session <br/>
*
* @param sessionId the unique ID for a session
* @param userId (optional) the internal user ID (not the username),
* can set this to null for an anonymous user or to remove the user binding from a session
* @param userEid (optional) the external user ID (typically the username),
* ignored if userId is null, must be set if userId is set
* @return the session with the given id
* @throws IllegalArgumentException if the sessionId is null or the session with that id cannot be found OR
* the userId is set and userEid is not set
*/
public Session bindSession(String sessionId, String userId, String userEid);
/**
* Retrieves a session by the sessionId if it is active <br/>
* WARNING: there is normally no need to call this method, use {@link #getCurrentSession()}
*
* @param sessionId the unique id for a session (not {@link Session#getId()}, this is {@link Session#getSessionId()})
* @return a session if one is available OR null if none found
* @throws IllegalArgumentException if the sessionId is null
*/
public Session getSession(String sessionId);
/**
* Get the list of sessions,
* this will automatically purge out any sessions which have expired
* @return the list of all active sessions ordered by last time accessed
*/
public List<Session> getAllActiveSessions();
/**
* Access the current session for the current thread,
* this contains information about the current user as well
*
* @return the Session object associated with the current request or processing thread OR null if there is not one
*/
public Session getCurrentSession();
/**
* Access the current session id for the current thread
* (also available from the current session)
*
* @return the id of the session associated with the current thread OR null if there is no session
*/
public String getCurrentSessionId();
/**
* Access the current user id for the current session
* (also available from the current session)
*
* @return the id of the user associated with the current thread OR null if there is no user
*/
public String getCurrentUserId();
}

View File

@@ -0,0 +1,130 @@
/*
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/services/model/Cache.java $
*
* $Revision: 3599 $
*
* $Date: 2009-03-17 00:23:54 -0700 (Tue, 17 Mar 2009) $
*
* Copyright (c) 2008, The DSpace Foundation. 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 DSpace Foundation 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
* HOLDERS 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.
*/
package org.dspace.services.model;
import java.util.List;
/**
* This is a cache which can be used to store data<br/>
* This is an abstraction of the general concept of a cache<br/>
* A Cache holds objects with keys with a limited lifespan and stores them based on the underlying implementation,
* this cache interface adheres to the JSR-107 spec
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface Cache {
/**
* Get the unique name which identifies this cache
* @return string
*/
public String getName();
/**
* Puts an object in the cache which is identified by this key,
* will overwrite an existing object if one is already using this key
* @param key the key for an item in the cache
* @param value an object (this can be a null, e.g. to cache a miss)
* @throws IllegalArgumentException if the cache name is invalid or cacheName or key is null
*/
public void put(String key, Object value);
/**
* Gets an object from the cache if it can be found (maybe be a null),
* use the exists check to see if the object is in the cache before retrieving
* @param key the key for an item in the cache
* @return the cached object (may be null) OR null if the cache object cannot be found
* @throws IllegalArgumentException if any arguments are null
*/
public Object get(String key);
/**
* Provides a method for finding out what keys are currently in the cache
* or getting all items out of the cache, the keys are returned in no
* particular order <br/>
* NOTE: that this is actually quite costly in most cases and should only be used when really needed,
* it is much better to fetch the items you actually need directly using {@link #get(String)}
*
* @return the list of all keys currently in this cache
*/
public List<String> getKeys();
/**
* Gets an object from the cache without causing it to be refreshed or renewed,
* like {@link #get(String)} except that it keeps the cache from refreshing the item that was retrieved
* @param key the key for an item in the cache
* @return the cached object (may be null) OR null if the cache object cannot be found
* @throws IllegalArgumentException if any arguments are null
* @see Cache#get(String)
*/
public Object look(String key);
/**
* Removes an object from the cache if it exists or does nothing if it does not
* @param key the key for an item in the cache
* @return true if the object was removed or false if it could not be found in the cache
* @throws IllegalArgumentException if any arguments are null
*/
public boolean remove(String key);
/**
* Check if a key exists in the cache and return true if it does
* @param key the key for an item in the cache
* @return true if the object was removed or false if it could not be found in the cache
* @throws IllegalArgumentException if any arguments are null
*/
public boolean exists(String key);
/**
* @return the count of the number of active items in the cache,
* does not include expired items
*/
public int size();
/**
* Clear out all cached items from this cache
*/
public void clear();
/**
* Returns a readable object which has the configuration used by this cache in it
* @return the object indicating the configuration of this cache
*/
public CacheConfig getConfig();
}

View File

@@ -0,0 +1,94 @@
/*
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/services/model/CacheConfig.java $
*
* $Revision: 3231 $
*
* $Date: 2008-10-24 02:10:30 -0700 (Fri, 24 Oct 2008) $
*
* Copyright (c) 2008, The DSpace Foundation. 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 DSpace Foundation 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
* HOLDERS 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.
*/
package org.dspace.services.model;
import org.dspace.services.CachingService;
/**
* Part of the {@link CachingService}<br/>
* Encodes the configuration for a cache into an object
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class CacheConfig {
/**
* Controls the scope of each created cache
*/
public enum CacheScope {
/**
* This cache is destroyed at the end of the current request for the current thread it was created in
*/
REQUEST,
/**
* This cache is destroyed when the current JVM shuts down
*/
INSTANCE,
/**
* This cache is destroyed when the entire cluster goes down,
* the cache will invalidate the same entries in other caches when it changes
*/
CLUSTERINVALIDATED,
/**
* This cache is destroyed when the entire cluster goes down,
* the cache will copy an entry over to other caches when it changes or is created
*/
CLUSTERREPLICATED;
};
/**
* Defines the lifecycle of the cache
* @see CacheScope
*/
private CacheScope cacheScope;
/**
* @return the scope of the associated cache
*/
public CacheScope getCacheScope() {
return cacheScope;
}
/**
* Configure the cache to use the given scope
* @param cacheScope defines the lifecycle of the cache
*/
public CacheConfig(CacheScope cacheScope) {
this.cacheScope = cacheScope;
}
}

View File

@@ -0,0 +1,76 @@
/**
* $Id: RequestInterceptor.java 3299 2008-11-18 14:22:36Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/services/model/RequestInterceptor.java $
* RequestInterceptor.java - DSpace2 - Oct 14, 2008 5:06:38 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.model;
import org.dspace.kernel.mixins.OrderedService;
/**
* Allows a developer to execute code at the beginning and/or end of system requests <br/>
* Note that the ordering of these must be set specifically higher than 0 or an exception will occur,
* if you do not really care what the order is you are encouraged to use 10 <br/>
* Note that the highest priority interceptor will be executed first in request start and
* last on request end. The lowest priority interceptor would be executed last on request start and
* first on request end. If you need an interceptor which can execute first on request start and
* first on request end (or vice versa) then create 2 interceptors. :-)
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface RequestInterceptor extends OrderedService {
/**
* Take actions before the request is handled for an operation,
* this will be called just before each request is sent to the correct request handler,
* for example: starting a transaction would happen at this point <br/>
* if you want to interrupt the handling of this request (stop it) then throw a {@link RequestInterruptionException}
*
* @param requestId the unique id of the request
* @param session the session associated with this request
* @throws RequestInterruptionException if this interceptor wants to stop the request
*/
public void onStart(String requestId, Session session);
/**
* Take actions after the request is handled for an operation,
* this will be called just before each operation is totally completed,
* for example: closing a transaction would happen at this point <br/>
* if you want to interrupt the handling of this request (stop it) then throw a {@link RequestInterruptionException} <br/>
* <b>NOTE:</b> it is important to realize that this will be called even if the request fails,
* please check the incoming success param to see if this request was successful or not,
* this is your cue to rollback or commit for example
*
* @param requestId the unique id of the request
* @param session the session associated with this request
* @param succeeded true if the request operations were successful, false if there was a failure
* @param failure this is the exception associated with the failure, it is null if there is no associated exception
*/
public void onEnd(String requestId, Session session, boolean succeeded, Exception failure);
/**
* This is a special exception types that is used to indicate that request processing should
* be halted, this should only be used in extreme cases as it will halt all request processing
* and cause any remaining interceptors to be skipped,
* a message about the halt should be placed into the message field
*/
public static class RequestInterruptionException extends RuntimeException {
private static final long serialVersionUID = 1L;
public RequestInterruptionException(String message, Throwable cause) {
super(message, cause);
}
public RequestInterruptionException(String message) {
super(message);
}
}
}

View File

@@ -0,0 +1,98 @@
/**
* $Id: Session.java 3246 2008-10-28 18:02:05Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/api/src/main/java/org/dspace/services/model/Session.java $
* Session.java - DSpace2 - Oct 14, 2008 11:46:22 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.model;
import java.util.Map;
import javax.servlet.http.HttpSession;
/**
* Represents a users session (login session) in the system, can hold some additional attributes as
* needed but the underlying implementation may limit the number and size of attributes to ensure
* session replication is not impacted negatively
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface Session extends HttpSession {
/**
* @return the session identifier, this is not the {@link #getId()} from HttpSession
* unless no session id was specified when the session was bound
*/
public String getSessionId();
/**
* @return internal user ID for the user using this session,
* this is null if the session is anonymous
*/
public String getUserId();
/**
* @return the external/enterprise user id of the user associated with this session
*/
public String getUserEID();
/**
* @return true if this session is active OR false if the session has timed out or been invalidated
*/
public boolean isActive();
/**
* @return id of the server which this session is associated with
*/
public String getServerId();
/**
* @return the IP Address from which this session originated
*/
public String getOriginatingHostIP();
/**
* @return the hostname from which this session originated
*/
public String getOriginatingHostName();
/**
* Get an attribute from the session if one exists
*
* @param key
* the key for the attribute
* @return the value if one exists OR null if none
*/
public String getAttribute(String key);
/**
* Set an attribute on a session
*
* @param key
* the key for the attribute
* @param value
* the value (if this is null then the attribute is removed)
*/
public void setAttribute(String key, String value);
/**
* @return a copy of the attributes in this session,
* modifying it has no effect on the session attributes
*/
public Map<String, String> getAttributes();
/**
* Purges all data from this session and effectively resets it to an anonymous session,
* does not invalidate the session though
*/
public void clear();
}

142
impl/pom.xml Normal file
View File

@@ -0,0 +1,142 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dspace</groupId>
<artifactId>dspace-services-impl</artifactId>
<name>DSpace Core IMPL</name>
<description>The implementation of the DSpace 2 services</description>
<url>http://projects.dspace.org</url>
<inceptionYear>Monday, September 1, 2008</inceptionYear>
<organization>
<name>The DSpace Foundation</name>
<url>http://www.dspace.org</url>
</organization>
<packaging>jar</packaging>
<parent>
<artifactId>dspace-services</artifactId>
<groupId>org.dspace</groupId>
<version>2.0.0-SNAPSHOT</version><!--dspace2.version-->
</parent>
<developers>
<developer>
<id>azeckoski</id>
<name>Aaron Zeckoski</name>
<email>azeckoski@gmail.com</email>
<organization>CARET, Univeristy of Cambridge</organization>
<organizationUrl>http://caret.cam.ac.uk/</organizationUrl>
<timezone>0</timezone>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
</developer>
<developer>
<id>mdiggory</id>
<name>Mark Diggory</name>
<email>mdiggory@gmail.com</email>
<organization>MIT Libraries, Massachusetts Institute of Technology</organization>
<organizationUrl>http://libraries.mit.edu</organizationUrl>
<timezone>+8</timezone>
<roles>
<role>architect</role>
</roles>
</developer>
</developers>
<!--
The Subversion repository location is used by Continuum to
update against when changes have occured, this spawns a new
build cycle and releases snapshots into the snapshot repository
below.
-->
<scm>
<connection>scm:svn:http://scm.dspace.org/svn/repo/modules/dspace-services/trunk/impl</connection>
<developerConnection>scm:svn:https://scm.dspace.org/svn/repo/modules/dspace-services/trunk/impl</developerConnection>
<url>http://scm.dspace.org/svn/repo/modules/dspace-services/trunk/impl</url>
</scm>
<repositories>
<repository>
<id>dspace-snapshot</id>
<name>DSpace Snapshot Repository</name>
<url>http://maven.dspace.org/snapshot</url>
<releases>
<enabled>false</enabled>
<checksumPolicy>fail</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-services-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-services-utils</artifactId>
</dependency>
<!-- logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- spring service manager -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<scope>compile</scope>
</dependency>
<!-- reflection -->
<dependency>
<groupId>org.azeckoski</groupId>
<artifactId>reflectutils</artifactId>
<scope>compile</scope>
</dependency>
<!-- this needs to eventually go into common/lib for tomcat 5 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<scope>compile</scope>
</dependency>
<!-- for filters -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- SPECIAL CASE - need JUNIT at build time and testing time -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.5</version>
<scope>provided</scope>
</dependency>
<!-- testing only -->
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-servlet-tester</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,311 @@
/**
* $Id: DSpaceKernelImpl.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/DSpaceKernelImpl.java $
* DSpaceKernelImpl.java - DSpace2 - Oct 6, 2008 2:55:53 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import java.lang.management.ManagementFactory;
import java.util.Date;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.Descriptor;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.modelmbean.DescriptorSupport;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import org.dspace.kernel.CommonLifecycle;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.DSpaceKernelManager;
import org.dspace.kernel.ServiceManager;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.dspace.services.ConfigurationService;
import org.dspace.utils.DSpace;
/**
* This is the kernel implementation which starts up the core of DSpace and
* registers the mbean and initializes the {@link DSpace} object,
* it also loads up the configuration <br/>
* Note that this does not start itself and calling the constuctor does not actually
* start it up either. It has to be explicitly started by calling the start method
* so something in the system needs to do that. If the bean is already started then calling start on
* it again has no effect. <br/>
* The name of this instance can be specified if desired.
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceKernelImpl implements DSpaceKernel, DynamicMBean, CommonLifecycle<DSpaceKernel> {
/**
* Creates a DSpace Kernel, does not do any checks though,
* do not call this, use {@link DSpaceKernelInit#getKernel(String)}
* @param name the name for the kernel
*/
protected DSpaceKernelImpl(String name) {
this.mBeanName = DSpaceKernelManager.checkName(name);
}
private String mBeanName = MBEAN_NAME;
private boolean running = false;
private boolean destroyed = false;
private final Object lock = new Object();
private DSpaceKernel kernel = null;
private Thread shutdownHook;
protected void registerShutdownHook() {
if (this.shutdownHook == null) {
synchronized (lock) {
// No shutdown hook registered yet
this.shutdownHook = new Thread() {
public void run() {
doDestroy();
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
}
private ConfigurationService configurationService;
public ConfigurationService getConfigurationService() {
return configurationService;
}
private ServiceManagerSystem serviceManagerSystem;
public ServiceManager getServiceManager() {
return serviceManagerSystem;
}
/* (non-Javadoc)
* @see org.dspace.kernel.DSpaceKernel#getMBeanName()
*/
public String getMBeanName() {
return mBeanName;
}
/* (non-Javadoc)
* @see org.dspace.kernel.DSpaceKernel#isRunning()
*/
public boolean isRunning() {
synchronized (lock) {
return running;
}
}
/* (non-Javadoc)
* @see org.dspace.kernel.CommonLifecycle#getManagedBean()
*/
public DSpaceKernel getManagedBean() {
synchronized (lock) {
return kernel;
}
}
/* (non-Javadoc)
* @see org.dspace.kernel.CommonLifecycle#start()
*/
public void start() {
// this starts up the entire core system
if (running) {
//log.warn("Kernel ("+this+") is already started");
return;
}
synchronized (lock) {
lastLoadDate = new Date();
long startTime = System.currentTimeMillis();
// create the configuration service and get the configuration
DSpaceConfigurationService dsConfigService = new DSpaceConfigurationService();
configurationService = dsConfigService;
// startup the service manager
serviceManagerSystem = new DSpaceServiceManager(dsConfigService);
serviceManagerSystem.startup();
// initialize the static
// DSpace.initialize(serviceManagerSystem);
loadTime = System.currentTimeMillis() - startTime;
kernel = this;
running = true;
// add in the shutdown hook
registerShutdownHook();
System.out.println("INFO DSpace kernel startup completed in "+loadTime+" ms and registered as MBean: " + mBeanName);
}
}
/* (non-Javadoc)
* @see org.dspace.kernel.CommonLifecycle#stop()
*/
public void stop() {
if (! running) {
//log.warn("Kernel ("+this+") is already stopped");
return;
}
synchronized (lock) {
// DSpace.initialize(null); // clear out the static cover
// wipe all the variables to free everything up
running = false;
kernel = null;
if (serviceManagerSystem != null) {
serviceManagerSystem.shutdown();
}
serviceManagerSystem = null;
configurationService = null;
// log completion (logger may be gone at this point so we cannot really use it)
System.out.println("INFO: DSpace kernel shutdown completed and unregistered MBean: " + mBeanName);
}
}
/* (non-Javadoc)
* @see org.dspace.kernel.CommonLifecycle#destroy()
*/
public void destroy() {
if (this.destroyed) {
return;
}
synchronized (lock) {
// stop the kernel
try {
stop();
} catch (Exception e) {
// oh well
}
// remove the mbean
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try {
ObjectName name = new ObjectName(mBeanName);
if (mbs.isRegistered(name)) {
mbs.unregisterMBean(name);
}
} catch (Exception e) {
// cannot use the logger here as it is already gone at this point
System.out.println("INFO: Failed to unregister the MBean: " + mBeanName);
}
// trash the shutdown hook as we do not need it anymore
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
this.shutdownHook = null;
} catch (Exception e) {
// ok, keep going
}
}
this.destroyed = true;
}
}
/**
* allows this to be called from within the shutdown thread
*/
protected void doDestroy() {
if (! this.destroyed) {
destroy();
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
try {
doDestroy();
} catch (Exception e) {
System.out.println("WARN Failure attempting to cleanup the DSpace kernel: " + e.getMessage());
}
}
@Override
public String toString() {
return "DSpaceKernel:" + mBeanName + ":lastLoad=" + lastLoadDate + ":loadTime=" + loadTime + ":running=" + running + ":kernel=" + (kernel == null ? null : kernel.getClass().getName() +"@"+kernel.getClass().getClassLoader() + ":" + super.toString());
}
// MBEAN methods
private Date lastLoadDate;
public Date getLastLoadDate() {
return new Date(lastLoadDate.getTime());
}
private long loadTime;
public long getLoadTime() {
return loadTime;
}
public Object invoke(String actionName, Object[] params, String[] signature)
throws MBeanException, ReflectionException {
return this;
}
public MBeanInfo getMBeanInfo() {
Descriptor lastLoadDateDesc = new DescriptorSupport(new String[] {"name=LastLoadDate",
"descriptorType=attribute", "default=0", "displayName=Last Load Date",
"getMethod=getLastLoadDate"});
Descriptor lastLoadTimeDesc = new DescriptorSupport(new String[] {"name=LastLoadTime",
"descriptorType=attribute", "default=0", "displayName=Last Load Time",
"getMethod=getLoadTime" });
ModelMBeanAttributeInfo[] mmbai = new ModelMBeanAttributeInfo[2];
mmbai[0] = new ModelMBeanAttributeInfo("LastLoadDate", "java.util.Date", "Last Load Date",
true, false, false, lastLoadDateDesc);
mmbai[1] = new ModelMBeanAttributeInfo("LastLoadTime", "java.lang.Long", "Last Load Time",
true, false, false, lastLoadTimeDesc);
ModelMBeanOperationInfo[] mmboi = new ModelMBeanOperationInfo[7];
mmboi[0] = new ModelMBeanOperationInfo("start", "Start DSpace Kernel", null, "void",
ModelMBeanOperationInfo.ACTION);
mmboi[1] = new ModelMBeanOperationInfo("stop", "Stop DSpace Kernel", null, "void",
ModelMBeanOperationInfo.ACTION);
mmboi[2] = new ModelMBeanOperationInfo("getManagedBean", "Get the Current Kernel", null,
DSpaceKernel.class.getName(), ModelMBeanOperationInfo.INFO);
return new ModelMBeanInfoSupport(this.getClass().getName(), "DSpace Kernel", mmbai, null, mmboi, null);
}
public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
if ("LastLoadDate".equals(attribute)) {
return getLastLoadDate();
} else if ("LastLoadTime".equals(attribute)) {
return getLoadTime();
}
throw new AttributeNotFoundException("invalid attribute: " + attribute);
}
public AttributeList getAttributes(String[] attributes) {
// TODO Auto-generated method stub
return null;
}
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException, MBeanException, ReflectionException {
throw new InvalidAttributeValueException("Cannot set attribute: " + attribute);
}
public AttributeList setAttributes(AttributeList attributes) {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -0,0 +1,175 @@
/**
* $Id: DSpaceKernelInit.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/DSpaceKernelInit.java $
* DSpaceKernelImpl.java - DSpace2 - Oct 6, 2008 2:55:53 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import java.lang.management.ManagementFactory;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.DSpaceKernelManager;
/**
* This class simplifies the handling of MBean lookup, registration, etc. of the DSpace Kernel MBean.
* This class has all static methods
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceKernelInit {
private static Object staticLock = new Object();
/**
* Creates or retrieves the existing DSpace Kernel with the given name
* @return a DSpace Kernel
* @throws IllegalStateException if the Kernel cannot be created
*/
public static DSpaceKernelImpl getKernel(String name) {
String mBeanName = DSpaceKernelManager.checkName(name);
synchronized (staticLock) {
DSpaceKernelImpl kernel = null;
try {
kernel = (DSpaceKernelImpl) getMBean(mBeanName);
} catch (IllegalStateException e) {
kernel = null;
}
if (kernel == null) {
DSpaceKernelImpl kernelImpl = new DSpaceKernelImpl(mBeanName);
System.out.println("INFO Created new kernel: " + kernelImpl);
// register the bean
String beanName = kernelImpl.getMBeanName();
register(beanName, kernelImpl);
kernel = kernelImpl;
}
return kernel;
}
}
/**
* Register a new kernel MBean with the given name or fail
* @param mBeanName the bean name to use
* @param kernel the kernel bean to register
* @throws IllegalStateException if the MBean cannot be registered
*/
public static void register(String mBeanName, DSpaceKernel kernel) {
mBeanName = DSpaceKernelManager.checkName(mBeanName);
synchronized (staticLock) {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try {
ObjectName name = new ObjectName(mBeanName);
if (! mbs.isRegistered(name)) {
// register the MBean
mbs.registerMBean(kernel, name);
System.out.println("INFO Registered new Kernel MBEAN: " + mBeanName + " ["+kernel+"]");
}
} catch (MalformedObjectNameException e) {
throw new IllegalStateException(e);
} catch (InstanceAlreadyExistsException e) {
throw new IllegalStateException(e);
} catch (MBeanRegistrationException e) {
throw new IllegalStateException(e);
} catch (NotCompliantMBeanException e) {
throw new IllegalStateException(e);
} catch (NullPointerException e) {
throw new IllegalStateException(e);
}
}
}
/**
* Unregister an MBean if possible
* @param mBeanName the bean name to use
* @return true if the MBean was unregistered, false otherwise
*/
public static boolean unregister(String mBeanName) {
mBeanName = DSpaceKernelManager.checkName(mBeanName);
synchronized (staticLock) {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try {
ObjectName name = new ObjectName(mBeanName);
mbs.unregisterMBean(name);
return true;
} catch (Exception e) {
System.out.println("WARN Failed to unregister the MBean: " + mBeanName);
return false;
}
}
}
/**
* Check if an MBean is registered already
* @param mBeanName the bean name to check
* @return true if registered OR false if not
* @throws IllegalStateException if a failure occurs
*/
public static boolean isRegistered(String mBeanName) {
mBeanName = DSpaceKernelManager.checkName(mBeanName);
boolean registered = false;
synchronized (staticLock) {
// register the mbean
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try {
ObjectName name = new ObjectName(mBeanName);
if (mbs.isRegistered(name)) {
registered = true;
}
} catch (MalformedObjectNameException e) {
throw new IllegalStateException(e);
} catch (NullPointerException e) {
throw new IllegalStateException(e);
}
}
return registered;
}
/**
* Gets the Kernel MBean if possible
* @param mBeanName the bean name to use
* @return the Kernel if found OR null if not found
* @throws IllegalStateException if a failure occurs
*/
public static DSpaceKernel getMBean(String mBeanName) {
mBeanName = DSpaceKernelManager.checkName(mBeanName);
DSpaceKernel kernel = null;
synchronized (staticLock) {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try {
ObjectName kernelName = new ObjectName(mBeanName);
kernel = (DSpaceKernel) mbs.invoke(kernelName, "getManagedBean", null, null);
kernel.isRunning(); // throws exception if the kernel is not running
} catch (InstanceNotFoundException e) {
kernel = null;
} catch (MBeanException e) {
kernel = null;
} catch (ReflectionException e) {
kernel = null;
} catch (MalformedObjectNameException e) {
kernel = null;
} catch (NullPointerException e) {
kernel = null;
}
}
return kernel;
}
}

View File

@@ -0,0 +1,613 @@
/**
* $Id: DSpaceServiceManager.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/DSpaceServiceManager.java $
* DSpaceServiceManager.java - DSpace2 - Oct 6, 2008 3:10:09 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.Map.Entry;
import org.azeckoski.reflectutils.ArrayUtils;
import org.azeckoski.reflectutils.ReflectUtils;
import org.azeckoski.reflectutils.map.ArrayOrderedMap;
import org.dspace.kernel.Activator;
import org.dspace.kernel.mixins.ConfigChangeListener;
import org.dspace.kernel.mixins.InitializedService;
import org.dspace.kernel.mixins.OrderedService;
import org.dspace.kernel.mixins.ServiceChangeListener;
import org.dspace.kernel.mixins.ServiceManagerReadyAware;
import org.dspace.kernel.mixins.ShutdownService;
import org.dspace.servicemanager.ServiceMixinManager.ServiceHolder;
import org.dspace.servicemanager.config.DSpaceConfig;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.dspace.servicemanager.spring.SpringServiceManager;
/**
* This is the core service manager which ties together the other
* service managers and generally handles any edge cases in the various systems
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceServiceManager implements ServiceManagerSystem {
private final DSpaceConfigurationService configurationService;
protected boolean running = false;
/**
* @return true if the service manager is running
*/
public boolean isRunning() {
return running;
}
/**
* Checks to see if the service manager is running, if not throws an exception
*/
private void checkRunning() {
if (! isRunning()) {
throw new IllegalStateException("Cannot perform operations on a service manager that is not running");
}
}
/**
* This will track all the service movement in the system and will maintain an accurate indication
* of the implemented apis and mixins for all services
* NOTE: Spring interceptor is handling the {@link InitializedService} and {@link ShutdownService} mixins,
* {@link ServiceChangeListener} and {@link ConfigChangeListener} mixins are handled here,
* the {@link OrderedService} mixin will be handled by the util class to assist with easily getting providers,
* all other mixins will be handled in the services that use them exclusively by accessing the {@link ServiceMixinManager}
* from this class directly
*/
private final ServiceMixinManager serviceMixinManager;
/**
* @return the current service mixin manager
*/
public ServiceMixinManager getServiceMixinManager() {
return serviceMixinManager;
}
private List<ServiceManagerSystem> serviceManagers = new Vector<ServiceManagerSystem>();
private SpringServiceManager primaryServiceManager = null;
/**
* This holds the stack of activators, it is randomly ordered
*/
private Vector<Activator> activators = new Vector<Activator>();
protected boolean developing = false;
/**
* Standard constructor
*/
public DSpaceServiceManager(DSpaceConfigurationService configurationService) {
if (configurationService == null) {
throw new IllegalArgumentException("Failure creating service manager, configuration service is null");
}
this.configurationService = configurationService;
this.developing = configurationService.getPropertyAsType("service.manager.developing", boolean.class);
this.serviceMixinManager = new ServiceMixinManager();
}
protected boolean testing = false;
protected String[] springXmlConfigFiles = null;
/**
* TESTING - This is for testing only
* @param springXmlConfigFiles
*/
protected DSpaceServiceManager(DSpaceConfigurationService configurationService, String... springXmlConfigFiles) {
this.configurationService = configurationService;
this.springXmlConfigFiles = springXmlConfigFiles;
this.testing = true;
this.developing = true;
this.serviceMixinManager = new ServiceMixinManager();
}
/**
* Registers the activators using this service manager
*/
private void registerActivators() {
// get out the list of all activators
List<DSpaceConfig> allConfigs = configurationService.getConfiguration();
List<DSpaceConfig> configs = new ArrayList<DSpaceConfig>();
for (DSpaceConfig config : allConfigs) {
if (config.isActivator()) {
configs.add(config);
}
}
// now startup and register all the activators
for (DSpaceConfig config : configs) {
String activatorClassName = config.getActivatorClassName();
Activator activator = null;
try {
Class<?> c = ServiceMixinManager.getClassByName(activatorClassName);
Object o = ReflectUtils.getInstance().constructClass(c);
activator = (Activator) o;
} catch (Exception e) {
System.err.println("ERROR: Failed to find and create activator with className ("+activatorClassName+"): " + e);
}
if (activator != null) {
// succeeded creating the activator
try {
activator.start(this);
activators.add(activator);
System.out.println("Started and registered activator: " + activatorClassName);
} catch (Exception e1) {
System.err.println("ERROR: Failed to start activator ("+activatorClassName+"): " + e1);
}
}
}
}
/**
* Unregisters all registered activators using this service manager
*/
private void unregisterActivators() {
for (Activator activator : activators) {
if (activator != null) {
String activatorClassName = activator.getClass().getName();
// succeeded creating the activator
try {
activator.stop(this);
System.out.println("Stopped and unregistered activator: " + activatorClassName);
} catch (Exception e1) {
System.err.println("ERROR: Failed to stop activator ("+activatorClassName+"): " + e1);
}
}
}
activators.clear();
}
/**
* Checks for service mixins and registers them in our keys set,
* finds out all the interfaces that are implemented by this service
* for future lookup, handles the service change listener
*
* @param name the name of the service
* @param service the service object
*/
public void registerServiceAPIs(String serviceName, Object service) {
checkRunning();
List<Class<?>> implementedTypes = serviceMixinManager.registerService(serviceName, service);
// handle the service registration listener
List<ServiceChangeListener> serviceChangeListeners =
getServiceMixinManager().getServicesByMixin(ServiceChangeListener.class);
for (ServiceChangeListener serviceChangeListener : serviceChangeListeners) {
// filter out this service so it does not get notified about its own registration
if (! service.equals(serviceChangeListener)) {
boolean notify = checkNotifyServiceChange(implementedTypes, serviceChangeListener);
if (notify) {
// only do the notification if filter allows
serviceChangeListener.serviceRegistered(serviceName, service, implementedTypes);
}
}
}
}
/**
* Clears out any existing mixin registration and handles the service change listener
* @param name the name of the service
*/
public void unregisterServiceAPIs(String serviceName) {
checkRunning();
Object service = serviceMixinManager.getServiceByName(serviceName);
List<Class<?>> implementedTypes = serviceMixinManager.unregisterServiceByName(serviceName);
if (service != null) {
// handle the service registration listener (after so the service leaving is gone already)
List<ServiceChangeListener> serviceChangeListeners =
getServiceMixinManager().getServicesByMixin(ServiceChangeListener.class);
for (ServiceChangeListener serviceChangeListener : serviceChangeListeners) {
boolean notify = checkNotifyServiceChange(implementedTypes, serviceChangeListener);
if (notify) {
// only do the notification if filter allows
serviceChangeListener.serviceUnregistered(serviceName, service);
}
}
}
}
/**
* This will call all the services which want to be notified when the service manager is ready
*/
public void notifyServiceManagerReady() {
List<ServiceManagerReadyAware> services = serviceMixinManager.getServicesByMixin(ServiceManagerReadyAware.class);
for (ServiceManagerReadyAware serviceManagerReadyAware : services) {
try {
serviceManagerReadyAware.serviceManagerReady(this);
} catch (Exception e) {
System.err.println("ERROR: Failure in service when calling serviceManagerReady: " + e);
}
}
}
/**
* Checks to see if a listener should be notified
* @param implementedTypes the types implemented by the service changing
* @param serviceChangeListener the listener
* @return true if it should be notified, false otherwise
*/
private boolean checkNotifyServiceChange(List<Class<?>> implementedTypes,
ServiceChangeListener serviceChangeListener) {
boolean notify = false;
Class<?>[] notifyTypes = serviceChangeListener.notifyForTypes();
if (notifyTypes == null || notifyTypes.length == 0) {
notify = true;
} else {
for (int i = 0; i < notifyTypes.length; i++) {
for (Class<?> implementedType : implementedTypes) {
if (notifyTypes[i].equals(implementedType)) {
notify = true;
break;
}
}
}
}
return notify;
}
public void shutdown() {
unregisterActivators();
for (ServiceManagerSystem sms : serviceManagers) {
try {
sms.shutdown();
} catch (Exception e) {
// shutdown failures are not great but should NOT cause an interruption of processing
System.err.println("Failure shutting down service manager ("+sms+"): " + e.getMessage());
}
}
this.running = false; // wait til the end
this.serviceManagers.clear();
this.serviceMixinManager.clear();
this.primaryServiceManager = null;
System.out.println("Shutdown DSpace core service manager");
}
public void startup() {
if (!testing) {
// try to load up extra config files for spring
String[] extraConfigs = configurationService.getPropertyAsType("service.manager.spring.configs", String[].class);
if (extraConfigs != null) {
if (springXmlConfigFiles == null) {
springXmlConfigFiles = extraConfigs;
} else {
springXmlConfigFiles = ArrayUtils.appendArrays(springXmlConfigFiles, extraConfigs);
}
}
}
try {
// have to put this at the top because otherwise initializing beans will die when they try to use the SMS
this.running = true;
// create the primary SMS and start it
SpringServiceManager springSMS = new SpringServiceManager(this, configurationService, testing, developing, springXmlConfigFiles);
try {
springSMS.startup();
} catch (Exception e) {
// startup failures are deadly
throw new IllegalStateException("failure starting up spring service manager: " + e.getMessage(), e);
}
// add it to the list of service managers
this.serviceManagers.add(springSMS);
this.primaryServiceManager = springSMS;
// register all the spring beans with the service mixin manager
Map<String, Object> springServices = primaryServiceManager.getServices();
for (Entry<String, Object> entry : springServices.entrySet()) {
String key = entry.getKey();
if (key != null && ! key.startsWith("org.springframework") ) {
this.serviceMixinManager.registerService(entry.getKey(), entry.getValue());
}
}
System.out.println("Registered "+this.serviceMixinManager.size()+" service's mixins from loaded core services");
// this kind of thing will be handled by DI utils -AZ
// // now start the secondary SMS using the spring bean factory
// String[] serviceManagerClasses = configurationService.getPropertyAsType("service.manager.external.classes", String[].class);
// if (serviceManagerClasses != null) {
// for (String serviceManagerClassName : serviceManagerClasses) {
// try {
// Class<ExternalServiceManagerSystem> smClass = (Class<ExternalServiceManagerSystem>)Class.forName(serviceManagerClassName);
// ExternalServiceManagerSystem eSMS = smClass.newInstance();
// eSMS.init(this, configurationService, testing, developing, serviceManagers);
// eSMS.startup();
//
// // add it to the list of service managers
// serviceManagers.add(eSMS);
// System.out.println("Started up DSpace external service manager: " + serviceManagerClassName);
// } catch (Exception e) {
// // startup failures are deadly
// throw new IllegalStateException("failure starting up service manager " + serviceManagerClassName + ": " + e.getMessage(), e);
// }
// }
// }
// now startup the activators
registerActivators();
// now we call the ready mixins
notifyServiceManagerReady();
} catch (Exception e) {
shutdown(); // execute the shutdown
String message = "Failed to startup the DSpace Service Manager: " + e.getMessage();
System.err.println(message);
throw new RuntimeException(message, e);
}
}
public void registerService(String name, Object service) {
checkRunning();
if (name == null || service == null) {
throw new IllegalArgumentException("name and service cannot be null");
}
// register service/provider with all
for (ServiceManagerSystem sms : serviceManagers) {
sms.registerService(name, service);
}
// find the mixins
registerServiceAPIs(name, service);
}
public <T> T registerServiceClass(String name, Class<T> type) {
checkRunning();
if (name == null || type == null) {
throw new IllegalArgumentException("name and type cannot be null");
}
// we only register with the primary
T service = primaryServiceManager.registerServiceClass(name, type);
registerServiceAPIs(name, service);
return service;
}
public void unregisterService(String name) {
checkRunning();
if (name == null) {
throw new IllegalArgumentException("name cannot be null");
}
// only unregister with the primary
primaryServiceManager.unregisterService(name);
unregisterServiceAPIs(name);
}
public <T> T getServiceByName(String name, Class<T> type) {
checkRunning();
if (type == null) {
throw new IllegalArgumentException("type cannot be null");
}
T service = null;
for (ServiceManagerSystem sms : serviceManagers) {
try {
service = sms.getServiceByName(name, type);
if (service != null) {
break;
}
} catch (Exception e) {
// keep going
}
}
// need to check the service mixin manager if not found
if (service == null
&& name != null) {
service = this.serviceMixinManager.getServiceByNameAndMixin(name, type);
}
return service;
}
public <T> List<T> getServicesByType(Class<T> type) {
checkRunning();
if (type == null) {
throw new IllegalArgumentException("type cannot be null");
}
HashSet<T> set = new HashSet<T>();
for (ServiceManagerSystem sms : serviceManagers) {
try {
set.addAll( sms.getServicesByType(type) );
} catch (Exception e) {
// keep going
}
}
// need to check the service mixin manager as well - NOTE: I think we might be able to avoid asking the SMSs at all and just use this -AZ
set.addAll( this.serviceMixinManager.getServicesByMixin(type) );
// put the set into a list for easier access and sort it
List<T> services = new ArrayList<T>(set);
Collections.sort(services, new ServiceMixinManager.ServiceComparator());
return services;
}
public List<String> getServicesNames() {
checkRunning();
List<String> names = new ArrayList<String>();
for (ServiceManagerSystem sms : serviceManagers) {
try {
names.addAll( sms.getServicesNames() );
} catch (Exception e) {
// keep going
}
}
Collections.sort(names);
return names;
}
public boolean isServiceExists(String name) {
checkRunning();
if (name == null) {
throw new IllegalArgumentException("name cannot be null");
}
boolean exists = false;
for (ServiceManagerSystem sms : serviceManagers) {
try {
exists = sms.isServiceExists(name);
if (exists) break;
} catch (Exception e) {
// keep going
}
}
return exists;
}
public Map<String, Object> getServices() {
checkRunning();
Map<String, Object> services = new HashMap<String, Object>();
for (ServiceManagerSystem sms : serviceManagers) {
try {
for (Entry<String, Object> entry : sms.getServices().entrySet()) {
if (! services.containsKey(entry.getKey())) {
services.put(entry.getKey(), entry.getValue());
}
}
} catch (Exception e) {
// keep going if it fails for one
System.err.println("Failed to get list of services from service manager ("+sms.getClass()+"): " + e);
}
}
return services;
}
/*
* Handles the configuration push for all services,
* every service gets called to notify them of the config change
* depending on the the listener they are using
*/
public void pushConfig(Map<String, String> properties) {
checkRunning();
if (properties != null && !properties.isEmpty()) {
// load in the new settings to the config service
String[] changedNames = configurationService.loadConfiguration(properties, false);
if (changedNames.length > 0) {
// some configs changed so push the changes to the listeners in all known services and providers
// make the list of changed setting names and map of changed settings
ArrayList<String> changedSettingNames = new ArrayList<String>();
ArrayOrderedMap<String, String> changedSettings = new ArrayOrderedMap<String, String>();
for (int i = 0; i < changedNames.length; i++) {
String configName = changedNames[i];
changedSettingNames.add(configName);
changedSettings.put( getSimplerName(configName), configurationService.getProperty(configName) );
}
// notify the services that implement the mixin
List<ServiceHolder<ConfigChangeListener>> configChangeListeners =
getServiceMixinManager().getServiceHoldersByMixin(ConfigChangeListener.class);
for (ServiceHolder<ConfigChangeListener> serviceHolder : configChangeListeners) {
String serviceName = serviceHolder.getServiceName();
ConfigChangeListener configChangeListener = serviceHolder.getService();
String serviceImplName = configChangeListener.getClass().getName();
// notify this service
try {
boolean notify = false;
String[] notifyNames = configChangeListener.notifyForConfigNames();
if (notifyNames == null || notifyNames.length == 0) {
notify = true;
} else {
for (int i = 0; i < notifyNames.length; i++) {
// check to see if the change was one of the bean properties for our service
String notifyName = getSimplerName(notifyNames[i]);
String notifyBeanName = DSpaceConfig.getBeanName(notifyNames[i]);
if (notifyBeanName != null) {
// this is a bean key
if (notifyBeanName.equals(serviceName) ||
notifyBeanName.equals(serviceImplName)) {
notify = true;
break;
}
}
// check to see if the name matches one of those the listener cares about
for (int j = 0; j < changedNames.length; j++) {
if (notifyName != null && notifyName.equals(changedNames[j])) {
notify = true;
break;
}
}
}
}
// do the notify if we should at this point
if (notify) {
configChangeListener.configurationChanged(changedSettingNames, changedSettings);
}
} catch (Exception e) {
System.err.println("Failure occurred while trying to notify service ("+serviceName+") of config change: " + e.getMessage());
}
}
}
}
}
/**
* @param key a DSpace config key
* @return the simpler name (property name or key without property)
*/
protected static String getSimplerName(String key) {
String simpleName = key;
if (key != null) {
String propertyName = DSpaceConfig.getBeanProperty(key);
if (propertyName != null) {
simpleName = propertyName;
}
}
return simpleName;
}
// STATICS
/**
* Adds configuration settings into services if possible,
* skips any that are invalid
*
* @param serviceName the name of the service
* @param service the service object
* @param serviceNameConfigs all known service configuration settings (from the DS config service impl)
*/
public static void configureService(String serviceName, Object service, Map<String, Map<String, ServiceConfig>> serviceNameConfigs) {
// stuff the config settings into the bean if there are any
if (serviceNameConfigs.containsKey(serviceName)) {
ReflectUtils reflectUtils = ReflectUtils.getInstance();
Map<String, ServiceConfig> configs = serviceNameConfigs.get(serviceName);
for (ServiceConfig config : configs.values()) {
try {
reflectUtils.setFieldValue(service, config.getParamName(), config.getValue());
System.out.println("Set param ("+config.getParamName()+") on service bean ("+serviceName+") to: " + config.getValue());
} catch (RuntimeException e) {
System.err.println("Unable to set param ("+config.getParamName()+") on service bean ("+serviceName+"): " + e.getMessage());
}
}
}
}
/**
* Initializes a service if it asks to be initialized or does nothing
* @param service any bean
* @throws IllegalStateException if the service init fails
*/
public static void initService(Object service) {
if (service instanceof InitializedService) {
try {
((InitializedService) service).init();
} catch (Exception e) {
throw new IllegalStateException("Failure attempting to initialize service (" + service + "): " + e.getMessage());
}
}
}
/**
* Shuts down a service if it asks to be shutdown or does nothing
* @param service any bean
*/
public static void shutdownService(Object service) {
if (service instanceof ShutdownService) {
try {
((ShutdownService) service).shutdown();
} catch (Exception e) {
System.err.println("Failure shutting down service: " + service);
}
}
}
}

View File

@@ -0,0 +1,24 @@
package org.dspace.servicemanager;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import java.util.List;
/**
* Interface for modular service manager systems.
* Provides a generic initialization routine, in leiu of hardcoded constructors
*/
public interface ExternalServiceManagerSystem extends ServiceManagerSystem {
/**
* Initialize the service manager's configuration
*
* @param parent
* @param configurationService
* @param testMode
* @param developmentMode
* @param serviceManagers
*/
void init(ServiceManagerSystem parent, DSpaceConfigurationService configurationService,
boolean testMode, boolean developmentMode, List<ServiceManagerSystem> serviceManagers);
}

View File

@@ -0,0 +1,44 @@
/**
* $Id: ServiceManagerSystem.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/ServiceManagerSystem.java $
* ServiceManagerSystem.java - DSpace2 - Oct 5, 2008 3:23:22 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import java.util.Map;
import org.dspace.kernel.ServiceManager;
/**
* This interface should be implemented by any service managers that we are using in the system,
* e.g. Spring, Guice
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface ServiceManagerSystem extends ServiceManager {
/**
* Startup the service manager and initialize all services
*/
public void startup();
/**
* Shuts down the service manager and all services that it is managing
*/
public void shutdown();
/**
* @return a map of name -> bean for all services that are currently known
*/
public Map<String, Object> getServices();
}

View File

@@ -0,0 +1,499 @@
/**
* $Id: ServiceMixinManager.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/ServiceMixinManager.java $
* EBlogic.java - entity-broker - Apr 15, 2008 4:29:18 PM - azeckoski
**************************************************************************
* Copyright (c) 2007, 2008 Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.osedu.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dspace.servicemanager;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.azeckoski.reflectutils.ReflectUtils;
import org.azeckoski.reflectutils.refmap.ReferenceMap;
import org.azeckoski.reflectutils.refmap.ReferenceType;
/**
* Borrowed from EntityBus since this already will handle the mixins for something correctly and easily,
* no need to reinvent this
*
* @author Aaron Zeckoski (aaronz@vt.edu)
*/
public class ServiceMixinManager {
/**
* This is a map from the serviceName only to the service and also
* from the bikey made from the serviceName AND the implemented interfaces and superclasses to the service,
* in other words, a service which implements 3 interfaces should have 4 entries in the map
*/
protected ReferenceMap<String, Object> serviceNameMap = new ReferenceMap<String, Object>(ReferenceType.STRONG, ReferenceType.SOFT);
/**
* Looks up a service by the well known name
* @param serviceName the well known and unique service name
* @return the service OR null if none can be found
*/
public Object getServiceByName(String serviceName) {
if (serviceName == null) {
throw new IllegalArgumentException("serviceName cannot be null");
}
// gets the main service registration
Object service = serviceNameMap.get(serviceName);
return service;
}
/**
* @param <T>
* @param serviceName the well known and unique service name
* @param mixin the class type of the implemented mixin interface
* @return the service which implements this mixin OR null if none can be found
*/
@SuppressWarnings("unchecked")
public <T extends Object> T getServiceByNameAndMixin(String serviceName, Class<T> mixin) {
if (serviceName == null) {
throw new IllegalArgumentException("serviceName cannot be null");
}
T service = null;
if (mixin == null) {
service = (T) getServiceByName(serviceName);
} else {
String bikey = getBiKey(serviceName, mixin);
service = (T) serviceNameMap.get(bikey);
}
return service;
}
/**
* @return the list of all known service names
*/
public List<String> getRegisteredServiceNames() {
Set<String> togo = new HashSet<String>();
for (String bikey : serviceNameMap.keySet()) {
if (bikey.indexOf('/') == -1) {
// main service regs only
togo.add(bikey);
}
}
ArrayList<String> names = new ArrayList<String>(togo);
Collections.sort(names);
return names;
}
/**
* @return all known registered services
*/
public List<Object> getRegisteredServices() {
Set<Object> togo = new HashSet<Object>();
for (Entry<String, Object> entry : serviceNameMap.entrySet()) {
String bikey = entry.getKey();
if (bikey.indexOf('/') == -1) {
// main service regs only
togo.add( entry.getValue() );
}
}
ArrayList<Object> services = new ArrayList<Object>(togo);
Collections.sort(services, new ServiceComparator());
return services;
}
/**
* @param serviceName the well known and unique service name
* @return the list of all known mixins for this service
*/
public List<Class<? extends Object>> getServiceMixins(String serviceName) {
if (serviceName == null) {
throw new IllegalArgumentException("serviceName cannot be null");
}
List<Class<? extends Object>> mixins = new ArrayList<Class<? extends Object>>();
for (String bikey : serviceNameMap.keySet()) {
String curPrefix = getServiceName(bikey);
if (curPrefix.equals(serviceName)
&& ! curPrefix.equals(bikey)) {
mixins.add( getMixin(bikey) );
}
}
Collections.sort(mixins, new ClassComparator());
return mixins;
}
/**
* WARNING: this is slow so do not use it unless you really need it!
* @return the map of all service names -> mixins that are currently registered
*/
public Map<String, List<Class<? extends Object>>> getRegisteredServiceMixins() {
Map<String, List<Class<? extends Object>>> m = new HashMap<String, List<Class<? extends Object>>>();
ArrayList<String> list = new ArrayList<String>( serviceNameMap.keySet() );
Collections.sort(list);
for (String bikey : list) {
String serviceName = getServiceName(bikey);
if (! m.containsKey(serviceName)) {
m.put(serviceName, new ArrayList<Class<? extends Object>>());
}
m.get(serviceName).add( getMixin(bikey) );
}
return m;
}
/**
* Allows retrieval of service and their names
* @param <T>
* @param mixin an interface which is a service mixin (technically any class)
* @return the list of all registered services wrapped in service holders which implement this mixin interface
*/
@SuppressWarnings("unchecked")
public <T extends Object> List<ServiceHolder<T>> getServiceHoldersByMixin(Class<T> mixin) {
if (mixin == null) {
throw new IllegalArgumentException("mixin cannot be null");
}
ArrayList<ServiceHolder<T>> services = new ArrayList<ServiceHolder<T>>();
String mixinName = mixin.getName();
for (Entry<String, Object> entry : serviceNameMap.entrySet()) {
String name = getMixinName(entry.getKey()); // name can be null
if (mixinName.equals(name)) {
String serviceName = getServiceName(entry.getKey());
services.add( new ServiceHolder<T>(serviceName, (T)entry.getValue()));
}
}
Collections.sort(services, new ServiceHolderComparator());
return services;
}
/**
* @param <T>
* @param mixin an interface which is a service mixin (technically any class)
* @return the list of all registered services which implement this mixin interface
*/
@SuppressWarnings("unchecked")
public <T extends Object> List<T> getServicesByMixin(Class<T> mixin) {
if (mixin == null) {
throw new IllegalArgumentException("mixin cannot be null");
}
ArrayList<T> services = new ArrayList<T>();
String mixinName = mixin.getName();
for (Entry<String, Object> entry : serviceNameMap.entrySet()) {
String name = getMixinName(entry.getKey()); // name can be null
if (mixinName.equals(name)) {
services.add((T)entry.getValue());
}
}
Collections.sort(services, new ServiceComparator());
return services;
}
/**
* Registers a service with the system and extracts all mixins,
* this will manage and track the mixins and the service
*
* @param serviceName the well known and unique service name
* @param service the service itself
* @return the list of mixin classes registered for this service
*/
public List<Class<?>> registerService(String serviceName, Object service) {
if (serviceName == null) {
throw new IllegalArgumentException("serviceName cannot be null");
}
if (service == null) {
throw new IllegalArgumentException("service cannot be null");
}
// blast any existing service registration under this name
unregisterServiceByName(serviceName);
List<Class<?>> classList = new ArrayList<Class<?>>();
// first we register the name against the service
registerPrefixCapability(serviceName, null, service);
// then register the name + its class against the service
registerPrefixCapability(serviceName, service.getClass(), service);
// then register all the mixin interfaces
List<Class<? extends Object>> superclasses = extractMixins(service);
int count = 0;
for (Class<? extends Object> superclazz : superclasses) {
registerPrefixCapability(serviceName, superclazz, service);
classList.add(superclazz);
count++;
// special handling for certain services if needed
// if (superclazz.equals(RequestAware.class)) {
// // need to shove in the requestGetter on registration
// ((RequestAware)service).setRequestGetter(requestGetter);
// }
}
System.out.println("INFO Registered service ("+service.getClass().getName()
+") serviceName ("+serviceName+") with "+count+" mixins");
return classList;
}
/**
* Unregisters a service and throws out all the mapped mixins
*
* @param serviceName the well known and unique service name
* @return the list of mixin classes registered for this service
*/
public List<Class<?>> unregisterServiceByName(String serviceName) {
// NOTE: this cannot be done with only an iterator as the reference map does not support it
List<Class<?>> classList = new ArrayList<Class<?>>();
List<String> keys = new ArrayList<String>();
for (Iterator<String> iterator = serviceNameMap.keySet().iterator(); iterator.hasNext();) {
String key = iterator.next();
if (key.startsWith(serviceName)) {
keys.add(key);
// get the class out of this key
try {
Class<?> mixin = getMixin(key);
classList.add(mixin);
} catch (Exception e) {
// could not get the mixin here, skip for now
continue;
}
}
}
// now remove the keys individually
for (String key : keys) {
serviceNameMap.remove(key);
}
return classList;
}
/**
* Unregisters a single mixin from a service
*
* @param serviceName the well known and unique service name
* @param mixin an interface which is a service mixin (technically any class)
*/
public void unregisterServiceMixin(String serviceName, Class<? extends Object> mixin) {
if (serviceName == null || mixin == null) {
throw new IllegalArgumentException("serviceName and mixin cannot be null");
}
if (Object.class.equals(mixin)) {
throw new IllegalArgumentException(
"Cannot separately unregister root Object mixin - use unregisterServiceByName instead");
}
String key = getBiKey(serviceName, mixin);
serviceNameMap.remove(key);
// do any cleanup that needs to be done when unregistering
// Nothing here right now
System.out.println("INFO Unregistered service mixin ("+mixin.getName()+") for serviceName ("+serviceName+")");
}
/**
* Allows for easy registration of a serviceName and mixin
*
* @param serviceName
* @param mixin
* @param service
* @return true if the service is newly registered, false if it was already registered
*/
public boolean registerPrefixCapability(String serviceName,
Class<? extends Object> mixin, Object entityProvider) {
String key = getBiKey(serviceName, mixin);
return serviceNameMap.put(key, entityProvider) == null;
}
/**
* Clears all service registrations
*
* @return the number of currently registered service names
*/
public int clear() {
// unregister all
int size = size();
serviceNameMap.clear();
return size;
}
/**
* @return the number of currently registered services
*/
public int size() {
int size = 0;
for (Entry<String, Object> entry : serviceNameMap.entrySet()) {
if (entry.getKey().indexOf('/') == -1) {
size++;
}
}
return size;
}
// STATICS - BIKEY methods
protected static String getBiKey(String serviceName, Class<? extends Object> clazz) {
if (serviceName == null) {
throw new IllegalArgumentException("serviceName must not be null");
}
if (serviceName.indexOf('/') > -1) {
throw new IllegalArgumentException("Service names cannot contain a '/' character");
}
String bikey = serviceName;
if (clazz != null) {
bikey = serviceName + "/" + clazz.getName();
}
return bikey;
}
protected static String getServiceName(String bikey) {
if (bikey == null) {
throw new IllegalArgumentException("bikey must not be null");
}
int slashpos = bikey.indexOf('/');
String serviceName = bikey;
if (slashpos > -1) {
serviceName = bikey.substring(0, slashpos);
}
return serviceName;
}
protected static String getMixinName(String bikey) {
if (bikey == null) {
throw new IllegalArgumentException("bikey must not be null");
}
int slashpos = bikey.indexOf('/');
String className = null;
if (slashpos > -1) {
className = bikey.substring(slashpos + 1);
}
return className;
}
protected static Class<? extends Object> getMixin(String bikey) {
String className = getMixinName(bikey);
return getClassByName(className);
}
// STATICS - OTHER
/**
* Attempts to get a class by name in the current classloader
* @param className the classname (fully qualified)
* @return the class object
* @throws RuntimeException if the class is not found
*/
public static Class<? extends Object> getClassByName(String className) {
Class<?> c = null;
if (className != null) {
try {
c = Class.forName(className);
} catch (ClassNotFoundException e) {
try {
c = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e1) {
throw new RuntimeException("Could not get Class from classname: " + className, e);
}
}
}
return (Class<? extends Object>) c;
}
/**
* Get the mixins implemented by this service,
* only gets interfaces and will not pick up superclasses <br/>
* WARNING: this is not the fastest ever
*
* @param service any object
* @return the list of services this class implements
*/
public static List<Class<? extends Object>> extractMixins(Object service) {
if (service == null) {
throw new IllegalArgumentException("service must not be null");
}
List<Class<?>> superclasses = ReflectUtils.getSuperclasses(service.getClass());
Set<Class<? extends Object>> capabilities = new HashSet<Class<? extends Object>>();
for (Class<?> superclazz : superclasses) {
if (superclazz.isInterface() && Object.class.isAssignableFrom(superclazz)) {
capabilities.add((Class<? extends Object>) superclazz);
}
}
return new ArrayList<Class<? extends Object>>(capabilities);
}
/**
* Compares based on the class name
*/
public static class ClassComparator implements Comparator<Class<?>>, Serializable {
public final static long serialVersionUID = 1l;
public int compare(Class<?> o1, Class<?> o2) {
if (o1 != null && o2 != null) {
return o1.getName().compareTo(o2.getName());
}
return 0;
}
}
/**
* Compares based on the class name
*/
public static class ServiceComparator implements Comparator<Object>, Serializable {
public final static long serialVersionUID = 1l;
public int compare(Object o1, Object o2) {
if (o1 != null && o2 != null) {
return o1.getClass().getName().compareTo(o2.getClass().getName());
}
return 0;
}
}
/**
* A class designed to carry services and their names for type safety
*/
public static class ServiceHolder<T> {
public String serviceName;
public T service;
/**
* @return the service object cast to the type requested (probably not the type of the actual object)
*/
public T getService() {
return service;
}
/**
* @return the name the service is registered under
*/
public String getServiceName() {
return serviceName;
}
public ServiceHolder(String serviceName, T service) {
if (serviceName == null || service == null) {
throw new IllegalArgumentException("Cannot construct service holder with null name or service");
}
this.serviceName = serviceName;
this.service = service;
}
@Override
public String toString() {
return serviceName+":"+service.getClass().getName()+":"+super.toString();
}
}
/**
* Compares based on the service
*/
public static class ServiceHolderComparator implements Comparator<ServiceHolder<?>>, Serializable {
public final static long serialVersionUID = 1l;
public int compare(ServiceHolder<?> o1, ServiceHolder<?> o2) {
return o1.getServiceName().compareTo(o2.getServiceName());
}
}
}

View File

@@ -14,6 +14,7 @@
package org.dspace.servicemanager.config;
import org.dspace.kernel.Activator;
/**
* This represents a single config setting for a DSpace instance

View File

@@ -0,0 +1,34 @@
/**
* $Id: ConcreteExample.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/example/ConcreteExample.java $
* ConcreteExample.java - DSpace2 - Oct 16, 2008 12:40:47 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.example;
/**
* Example of a concrete example to fire up as a service,
* this is fired up using XML in the case of spring (though it does not have to be)
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class ConcreteExample {
private String name = "azeckoski";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -0,0 +1,35 @@
/**
* $Id: ServiceExample.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/example/ServiceExample.java $
* ServiceExample.java - DSpace2 - Oct 16, 2008 12:29:26 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.example;
/**
* Sample service
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface ServiceExample {
/**
* @return some string for testing
*/
public String getName();
/**
* @return some string from another service
*/
public String getOtherName();
}

View File

@@ -0,0 +1,49 @@
/**
* $Id: ServiceExampleImpl.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/example/ServiceExampleImpl.java $
* ServiceExampleImpl.java - DSpace2 - Oct 16, 2008 12:29:15 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Service;
/**
* Example impl of the example service
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
@Service // for Spring
public class ServiceExampleImpl implements ServiceExample {
private ConcreteExample concreteExample;
@Autowired // Spring
@Required // Spring
public void setConcreteExample(ConcreteExample concreteExample) {
this.concreteExample = concreteExample;
}
private String name = "aaronz";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOtherName() {
return concreteExample.getName();
}
}

View File

@@ -0,0 +1,121 @@
/*
* $URL: $
*
* $Revision: $
*
* $Date: $
*
* Copyright (c) 2008, The DSpace Foundation. 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 DSpace Foundation 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
* HOLDERS 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.
*/
package org.dspace.servicemanager.servlet;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.dspace.servicemanager.DSpaceKernelImpl;
import org.dspace.servicemanager.DSpaceKernelInit;
/**
* This servlet context listener will handle startup of the kernel if it is not there,
* shutdown of the context listener does not shutdown the kernel though,
* that is tied to the shutdown of the JVM <br/>
*
* This is implemented in the web application web.xml using:
*
* <web-app>
*
* <listener>
* <listener-class>
* org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener
* </listener-class>
*</listener>
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
* @author Mark Diggory (mdiggory @ gmail.com)
*/
public class DSpaceKernelServletContextListener implements ServletContextListener {
private transient DSpaceKernelImpl kernelImpl;
/* (non-Javadoc)
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent arg0)
{
// start the kernel when the webapp starts
try {
this.kernelImpl = DSpaceKernelInit.getKernel(null);
if (! this.kernelImpl.isRunning()) {
this.kernelImpl.start(); // init the kernel
}
} catch (Exception e) {
// failed to start so destroy it and log and throw an exception
try {
this.kernelImpl.destroy();
} catch (Exception e1) {
// nothing
}
String message = "Failure during filter init: " + e.getMessage();
System.err.println(message + ":" + e);
throw new RuntimeException(message, e);
}
}
/* (non-Javadoc)
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent arg0)
{
// currently we are stopping the kernel when the webapp stops
if (this.kernelImpl != null) {
this.kernelImpl.destroy();
this.kernelImpl = null;
}
// No longer going to use JCL
// // clean up the logger for this webapp
// LogFactory.release(Thread.currentThread().getContextClassLoader());
// No longer cleaning this up here since it causes failures
// // cleanup the datasource
// try {
// for (Enumeration<?> e = DriverManager.getDrivers(); e.hasMoreElements(); ) {
// Driver driver = (Driver) e.nextElement();
// if (driver.getClass().getClassLoader() == getClass().getClassLoader()) {
// DriverManager.deregisterDriver(driver);
// }
// }
// } catch (Throwable e) {
// System.err.println("Unable to clean up JDBC driver: " + e.getMessage());
// }
}
}

View File

@@ -0,0 +1,105 @@
/**
* $Id: DSpaceBeanFactoryPostProcessor.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/spring/DSpaceBeanFactoryPostProcessor.java $
* ForceLazyBeanFactoryPostProcessor.java - DSpace2 - Oct 5, 2008 9:53:13 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.spring;
import java.util.ArrayList;
import java.util.List;
import org.dspace.servicemanager.ServiceManagerSystem;
import org.dspace.servicemanager.ServiceMixinManager;
import org.dspace.servicemanager.config.DSpaceConfig;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
/**
* This will allow us to put the configuration into beans as they are being created,
* it also handles activator classes from the configuration
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
private DSpaceConfigurationService configurationService;
private ServiceManagerSystem parent;
private boolean testMode = false;
public DSpaceBeanFactoryPostProcessor(ServiceManagerSystem parent,
DSpaceConfigurationService configurationService, boolean testMode) {
if (parent == null || configurationService == null) {
throw new IllegalArgumentException("parent and configuration service cannot be null");
}
this.configurationService = configurationService;
this.parent = parent;
this.testMode = testMode;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
*/
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// force config service to be registered first
beanFactory.registerSingleton(ConfigurationService.class.getName(), configurationService);
beanFactory.registerSingleton(ServiceManagerSystem.class.getName(), parent);
// register any beans which need to be registered now
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// get out the list of all activator classes
List<DSpaceConfig> allConfigs = configurationService.getConfiguration();
List<DSpaceConfig> configs = new ArrayList<DSpaceConfig>();
for (DSpaceConfig config : allConfigs) {
if (config.isActivatorClass()) {
configs.add(config);
}
}
if (testMode) {
System.out.println("TEST Spring Service Manager running in test mode, no activators will be started");
} else {
// now register all autowire configured beans
for (DSpaceConfig config : configs) {
try {
Class<?> c = ServiceMixinManager.getClassByName(config.getActivatorClassName());
String autowire = config.getActivatorAutowire();
int autowireSpring = AbstractBeanDefinition.AUTOWIRE_AUTODETECT;
if ("none".equals(autowire)) {
autowireSpring = AbstractBeanDefinition.AUTOWIRE_NO;
} else if ("constructor".equals(autowire)) {
autowireSpring = AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR;
} else if ("setter".equals(autowire)) {
autowireSpring = AbstractBeanDefinition.AUTOWIRE_BY_TYPE;
}
RootBeanDefinition beanDef = new RootBeanDefinition(c, autowireSpring);
beanDef.setScope(AbstractBeanDefinition.SCOPE_SINGLETON);
registry.registerBeanDefinition(config.getActivatorName(), beanDef);
} catch (Exception e) {
System.err.println("Failed to register activator class from config: " + config + " :" + e);
}
}
}
// System.out.println("Registered beans: " + registry.getBeanDefinitionCount());
// String[] bns = registry.getBeanDefinitionNames();
// for (String bn : bns) {
// BeanDefinition bd = registry.getBeanDefinition(bn);
// System.out.println(" - " + bd.getBeanClassName() + ":" + bd.getDescription() );
// }
}
}

View File

@@ -0,0 +1,66 @@
/**
* $Id: DSpaceBeanPostProcessor.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/spring/DSpaceBeanPostProcessor.java $
* DSpaceBeanPostProcessor.java - DSpace2 - Oct 23, 2008 12:48:11 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.spring;
import org.dspace.servicemanager.DSpaceServiceManager;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
/**
* This processes beans as they are loaded into the system by spring,
* allows us to handle the init method and also push config options
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceBeanPostProcessor implements BeanPostProcessor, DestructionAwareBeanPostProcessor {
private DSpaceConfigurationService configurationService;
@Autowired
public DSpaceBeanPostProcessor(DSpaceConfigurationService configurationService) {
if (configurationService == null) {
throw new IllegalArgumentException("configuration service cannot be null");
}
this.configurationService = configurationService;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
*/
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
DSpaceServiceManager.configureService(beanName, bean, configurationService.getServiceNameConfigs());
return bean;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
*/
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
DSpaceServiceManager.initService(bean);
return bean;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction(java.lang.Object, java.lang.String)
*/
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
DSpaceServiceManager.shutdownService(bean);
}
}

View File

@@ -0,0 +1,238 @@
/**
* $Id: ResourceFinder.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/spring/ResourceFinder.java $
* ResourceFinder.java - caching - May 29, 2008 11:59:02 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.spring;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
/**
* Takes a list of paths to resources and turns them into different things (file/IS/resource),
* this also allows us to look on a relative or absolute path and will automatically
* check the typical places one might expect to put dspace config files<br/>
*
* @author Aaron Zeckoski (aaron@caret.cam.ac.uk)
*/
public class ResourceFinder {
public static final String relativePath = DSpaceConfigurationService.DSPACE + "/";
public static final String environmentPathVariable = DSpaceConfigurationService.DSPACE_HOME;
private static List<Resource> makeResources(List<String> paths) {
List<Resource> rs = new ArrayList<Resource>();
if (paths != null && !paths.isEmpty()) {
for (String path : paths) {
try {
Resource r = makeResource(path);
rs.add(r);
} catch (IllegalArgumentException e) {
// do not add if not found, just skip
System.out.println("WARN: " + e.getMessage() + ", continuing...");
}
}
}
return rs;
}
private static Resource makeResource(String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
Resource r = findResource(path);
if (! r.exists()) {
// try to find just the fileName
// get the fileName from the path
int fileStart = path.lastIndexOf('/') + 1;
String fileName = path.substring(fileStart);
r = findResource(fileName);
}
// try the environment path first
if (! r.exists()) {
throw new IllegalArgumentException("Could not find this resource ("+path+") in any of the checked locations");
}
return r;
}
private static Resource findResource(String path) {
Resource r;
String envPath = getEnvironmentPath() + path;
r = new FileSystemResource(envPath);
if (! r.exists()) {
// try the relative path next
String relPath = getRelativePath() + path;
r = new FileSystemResource(relPath);
if (! r.exists()) {
// now try the classloaders
ClassLoader cl = ResourceFinder.class.getClassLoader();
r = new ClassPathResource(path, cl);
if (! r.exists()) {
// finally try the context classloader
cl = Thread.currentThread().getContextClassLoader();
r = new ClassPathResource(path, cl);
}
}
}
return r;
}
/**
* Resolves a list of paths into resources relative to environmental defaults or relative paths or the classloader
* @param paths a list of paths to resources (org/sakaiproject/mystuff/Thing.xml)
* @return an array of Spring Resource objects
*/
public static Resource[] getResources(List<String> paths) {
return makeResources(paths).toArray(new Resource[] {});
}
public static File[] getFiles(List<String> paths) {
List<Resource> rs = makeResources(paths);
File[] files = new File[rs.size()];
for (int i = 0; i < rs.size(); i++) {
Resource r = rs.get(i);
try {
files[i] = r.getFile();
} catch (IOException e) {
throw new RuntimeException("Failed to get file for: " + r.getFilename(), e);
}
}
return files;
}
public static InputStream[] getInputStreams(List<String> paths) {
List<Resource> rs = makeResources(paths);
InputStream[] streams = new InputStream[rs.size()];
for (int i = 0; i < rs.size(); i++) {
Resource r = rs.get(i);
try {
streams[i] = r.getInputStream();
} catch (IOException e) {
throw new RuntimeException("Failed to get inputstream for: " + r.getFilename(), e);
}
}
return streams;
}
/**
* Resolve a path into a resource relative to environmental defaults or relative paths or the classloader
* @param path a path to a resource (org/dspace/mystuff/Thing.xml)
* @return the Spring Resource object
* @throws IllegalArgumentException if no resource can be found
*/
public static Resource getResource(String path) {
if (path == null) {
throw new IllegalArgumentException("Invalid null path");
}
Resource r = makeResource(path);
return r;
}
/**
* Attempt to resolve multiple paths in order until one is found
* @param paths an array of paths to a resource (org/dspace/mystuff/Thing.xml)
* @return the Spring Resource object
* @throws IllegalArgumentException if no resource can be found
*/
public static Resource getResourceFromPaths(String[] paths) {
if (paths == null) {
throw new IllegalArgumentException("Invalid null paths");
}
Resource r = null;
for (int i = 0; i < paths.length; i++) {
try {
r = makeResource(paths[i]);
} catch (IllegalArgumentException e) {
continue;
}
break;
}
if (r == null) {
throw new IllegalArgumentException("Could not find any resource from paths (" + Arrays.toString(paths) + ") in any of the checked locations");
}
return r;
}
public static File getFile(String path) {
Resource r = getResource(path);
File f = null;
try {
f = r.getFile();
} catch (IOException e) {
throw new RuntimeException("Failed to get file for: " + r.getFilename(), e);
}
return f;
}
public static InputStream getInputStream(String path) {
Resource r = getResource(path);
InputStream is = null;
try {
is = r.getInputStream();
} catch (IOException e) {
throw new RuntimeException("Failed to get inputstream for: " + r.getFilename(), e);
}
return is;
}
protected static String getRelativePath() {
File currentPath = new File("");
File f = new File(currentPath, relativePath);
if (! f.exists() || ! f.isDirectory()) {
f = new File(currentPath, DSpaceConfigurationService.DSPACE);
if (! f.exists() || ! f.isDirectory()) {
f = currentPath;
}
}
String absPath = f.getAbsolutePath();
if (! absPath.endsWith(File.separatorChar + "")) {
absPath += File.separatorChar;
}
return absPath;
}
protected static String getEnvironmentPath() {
String envPath = System.getenv(environmentPathVariable);
if (envPath == null) {
envPath = System.getProperty(environmentPathVariable);
if (envPath == null) {
String container = getContainerHome();
if (container == null) {
container = "";
}
envPath = container + File.separatorChar + DSpaceConfigurationService.DSPACE + File.separatorChar;
}
}
return envPath;
}
/**
* @return the container home if one can be found
*/
public static String getContainerHome() {
String catalina = System.getProperty("catalina.base");
if (catalina == null) {
catalina = System.getProperty("catalina.home");
}
return catalina;
}
}

View File

@@ -0,0 +1,306 @@
/**
* $Id: SpringServiceManager.java 3887 2009-06-18 03:45:35Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/servicemanager/spring/SpringServiceManager.java $
* SpringServiceManager.java - DSpace2 - Oct 5, 2008 8:26:59 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.spring;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.dspace.servicemanager.DSpaceServiceManager;
import org.dspace.servicemanager.ServiceManagerSystem;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* This is the Spring implementation of the service manager
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class SpringServiceManager implements ServiceManagerSystem {
private static Logger log = LoggerFactory.getLogger(SpringServiceManager.class);
private ClassPathXmlApplicationContext applicationContext;
/**
* @return the parent core Spring {@link ApplicationContext}
*/
public ClassPathXmlApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* @return the current spring bean factory OR null if there is not one
*/
public ListableBeanFactory getBeanFactory() {
if (applicationContext != null) {
return applicationContext.getBeanFactory();
}
return null;
}
private final ServiceManagerSystem parent;
private final DSpaceConfigurationService configurationService;
private boolean testMode = false;
private boolean developmentMode = false;
private String[] configPaths = null;
/**
* For TESTING:
* Allows adding extra spring config paths
* @param testMode if true then do not load the core beans
* @param configPaths additional spring config paths within this classloader
*/
public SpringServiceManager(ServiceManagerSystem parent, DSpaceConfigurationService configurationService, boolean testMode, boolean developmentMode, String... configPaths) {
if (parent == null) {
throw new IllegalArgumentException("parent SMS cannot be null");
}
this.parent = parent;
if (configurationService == null) {
throw new IllegalArgumentException("configuration service cannot be null");
}
this.configurationService = configurationService;
this.testMode = testMode;
this.developmentMode = developmentMode;
this.configPaths = configPaths;
}
public static final String configPath = "spring/applicationContext.xml";
public static final String corePath = "spring/spring-dspace-core-services.xml";
/**
* Spring does not actually allow us to add in new singletons which have bean definitions so we
* have to track the added singleton names ourselves manually
*/
private Vector<String> singletonNames = new Vector<String>();
@SuppressWarnings("unchecked")
public <T> T getServiceByName(String name, Class<T> type) {
T bean = null;
// handle special case to return the core AC
if (ApplicationContext.class.getName().equals(name)
&& ApplicationContext.class.isAssignableFrom(type)) {
bean = (T) getApplicationContext();
} else {
if (name != null) {
// get by name and type
try {
bean = (T) applicationContext.getBean(name, type);
} catch (BeansException e) {
// no luck, try the fall back option
bean = null;
}
} else {
// try making up the name based on the type
try {
bean = (T) applicationContext.getBean(type.getName(), type);
} catch (BeansException e) {
// no luck, try the fall back option
bean = null;
}
}
// if still no luck then try by type only
if (name == null
&& bean == null) {
try {
Map<String, Object> map = applicationContext.getBeansOfType(type);
if (map.size() == 1) {
// only return the bean if there is exactly one
bean = (T) map.values().iterator().next();
}
} catch (BeansException e) {
// I guess there are no beans of this type
bean = null;
}
}
}
return bean;
}
@SuppressWarnings("unchecked")
public <T> List<T> getServicesByType(Class<T> type) {
ArrayList<T> l = new ArrayList<T>();
Map<String, Object> beans;
try {
beans = applicationContext.getBeansOfType(type, true, true);
l.addAll( (Collection<? extends T>) beans.values() );
} catch (BeansException e) {
throw new RuntimeException("Failed to get beans of type ("+type+"): " + e.getMessage(), e);
}
return l;
}
public void shutdown() {
if (applicationContext != null) {
try {
applicationContext.close();
} catch (Exception e) {
// keep going anyway
e.printStackTrace();
}
try {
applicationContext.destroy();
} catch (Exception e) {
// keep going anyway
e.printStackTrace();
}
applicationContext = null;
log.info("Spring Service Manager Shutdown...");
}
}
public void startup() {
long startTime = System.currentTimeMillis();
// get all spring config paths
ArrayList<String> pathList = new ArrayList<String>();
pathList.add(configPath);
if (testMode) {
log.warn("TEST Spring Service Manager running in test mode, no core beans will be started");
} else {
// only load the core beans when not testing the service manager
pathList.add(corePath);
}
if (configPaths != null) {
for (int i = 0; i < configPaths.length; i++) {
pathList.add(configPaths[i]);
}
}
String[] allPaths = pathList.toArray(new String[pathList.size()]);
applicationContext = new ClassPathXmlApplicationContext(allPaths, false);
// disable poor practices
applicationContext.setAllowBeanDefinitionOverriding(false);
applicationContext.setAllowCircularReferences(false);
//applicationContext.registerShutdownHook(); // this interferes with the kernel shutdown hook
// add the config interceptors (partially done in the xml)
applicationContext.addBeanFactoryPostProcessor( new DSpaceBeanFactoryPostProcessor(parent, configurationService, testMode) );
applicationContext.refresh();
if (developmentMode) {
log.warn("Spring Service Manager is running in developmentMode, services will be loaded on demand only");
// TODO find a way to set this sucker to super duper lazy mode? it is currently not actually doing it
} else {
applicationContext.getBeanFactory().preInstantiateSingletons();
applicationContext.getBeanFactory().freezeConfiguration();
}
long totalTime = System.currentTimeMillis() - startTime;
log.info("Spring Service Manager started up in "+totalTime+" ms with "+applicationContext.getBeanDefinitionCount()+" services...");
}
@SuppressWarnings("unchecked")
public <T> T registerServiceClass(String name, Class<T> type) {
if (name == null || type == null) {
throw new IllegalArgumentException("name and type must not be null for service registration");
}
T service;
try {
service = (T) applicationContext.getBeanFactory().autowire(type, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
registerBean(name, service);
} catch (BeansException e) {
throw new IllegalArgumentException("Invalid service class ("+type+") with name ("+name+") registration: " + e.getMessage(), e);
}
return service;
}
public void registerService(String name, Object service) {
if (name == null || service == null) {
throw new IllegalArgumentException("name and service must not be null for service registration");
}
try {
applicationContext.getBeanFactory().autowireBean(service);
} catch (BeansException e) {
throw new IllegalArgumentException("Invalid service ("+service+") with name ("+name+") registration: " + e.getMessage(), e);
}
registerBean(name, service);
}
/**
* This handles the common part of the 2 types of service registrations
* @param name
* @param service
*/
private void registerBean(String name, Object service) {
try {
applicationContext.getBeanFactory().initializeBean(service, name);
applicationContext.getBeanFactory().registerSingleton(name, service);
} catch (BeansException e) {
throw new IllegalArgumentException("Invalid service ("+service+") with name ("+name+") registration: " + e.getMessage(), e);
}
singletonNames.add(name);
}
public void unregisterService(String name) {
singletonNames.remove(name);
if (applicationContext.containsBean(name)) {
try {
Object beanInstance = applicationContext.getBean(name);
try {
applicationContext.getBeanFactory().destroyBean(name, beanInstance);
} catch (NoSuchBeanDefinitionException e) {
// this happens if the bean was registered manually (annoyingly)
DSpaceServiceManager.shutdownService(beanInstance);
}
} catch (BeansException e) {
// nothing to do here, could not find the bean
}
}
}
public List<String> getServicesNames() {
ArrayList<String> beanNames = new ArrayList<String>();
beanNames.addAll(singletonNames);
String[] singletons = applicationContext.getBeanFactory().getSingletonNames();
for (int i = 0; i < singletons.length; i++) {
if (singletons[i].startsWith("org.springframework.context")) {
continue; // skip the spring standard ones
}
beanNames.add(singletons[i]);
}
Collections.sort(beanNames);
return beanNames;
}
public boolean isServiceExists(String name) {
boolean exists = applicationContext.containsBean(name);
return exists;
}
public Map<String, Object> getServices() {
Map<String, Object> services = new HashMap<String, Object>();
String[] singletons = applicationContext.getBeanFactory().getSingletonNames();
for (int i = 0; i < singletons.length; i++) {
if (singletons[i].startsWith("org.springframework.context")) {
continue; // skip the spring standard ones
}
String beanName = singletons[i];
Object service = applicationContext.getBeanFactory().getSingleton(beanName);
if (service == null) {
continue;
}
services.put(beanName, service);
}
return services;
}
public void pushConfig(Map<String, String> settings) {
throw new UnsupportedOperationException("Not implemented for individual service manager systems");
}
}

View File

@@ -0,0 +1,567 @@
/**
* $Id: CachingServiceImpl.java 3688 2009-04-07 10:06:23Z grahamtriggs $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/services/caching/CachingServiceImpl.java $
* CachingServiceImpl.java - DSpace2 - Oct 23, 2008 10:38:23 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.caching;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.management.MBeanServer;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Statistics;
import net.sf.ehcache.management.ManagementService;
import org.dspace.kernel.ServiceManager;
import org.dspace.kernel.mixins.ConfigChangeListener;
import org.dspace.kernel.mixins.InitializedService;
import org.dspace.kernel.mixins.ServiceChangeListener;
import org.dspace.kernel.mixins.ShutdownService;
import org.dspace.providers.CacheProvider;
import org.dspace.services.CachingService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.caching.model.EhcacheCache;
import org.dspace.services.caching.model.MapCache;
import org.dspace.services.model.Cache;
import org.dspace.services.model.CacheConfig;
import org.dspace.services.model.CacheConfig.CacheScope;
import org.dspace.utils.servicemanager.ProviderHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
/**
* This is the core caching service which is available for anyone who is writing code for DSpace to use
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class CachingServiceImpl implements CachingService, InitializedService, ShutdownService, ConfigChangeListener, ServiceChangeListener {
private static Logger log = LoggerFactory.getLogger(CachingServiceImpl.class);
/**
* This is the event key for a full cache reset
*/
protected static final String EVENT_RESET = "caching.reset";
/**
* The default config location
*/
protected static final String DEFAULT_CONFIG = "org/dspace/services/caching/ehcache-config.xml";
/**
* all the non-thread caches that we know about,
* mostly used for tracking purposes
*/
private Map<String, EhcacheCache> cacheRecord = new ConcurrentHashMap<String, EhcacheCache>();
/**
* All the request caches, this is bound to the thread,
* the initial value of this TL is set automatically when it is created
*/
private ThreadLocal<Map<String, MapCache>> requestMap = new ThreadLocalMap();
/**
* @return the current request map which is bound to the current thread
*/
protected Map<String, MapCache> getRequestMap() {
return requestMap.get();
}
/**
* Unbinds all request caches, destroys the caches completely
*/
public void unbindRequestCaches() {
// not sure if I really need to clear these first, it should be sufficient to just wipe the request map -AZ
for (MapCache mc : requestMap.get().values()) {
mc.clear();
}
requestMap.remove(); // clear the TL entirely
}
private ConfigurationService configurationService;
@Autowired
@Required
public void setConfigurationService(ConfigurationService configurationService) {
this.configurationService = configurationService;
}
private ServiceManager serviceManager;
@Autowired
@Required
public void setServiceManager(ServiceManager serviceManager) {
this.serviceManager = serviceManager;
}
/** The underlying cache manager; injected */
protected net.sf.ehcache.CacheManager cacheManager;
@Autowired
@Required
public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
public net.sf.ehcache.CacheManager getCacheManager() {
return cacheManager;
}
public boolean useClustering = false;
public boolean useDiskStore = true;
public int maxElementsInMemory = 2000;
public int timeToLiveSecs = 3600;
public int timeToIdleSecs = 600;
/**
* Reloads the config settings from the configuration service
*/
protected void reloadConfig() {
useClustering = configurationService.getPropertyAsType(knownConfigNames[0], boolean.class);
useDiskStore = configurationService.getPropertyAsType(knownConfigNames[1], boolean.class);
maxElementsInMemory = configurationService.getPropertyAsType(knownConfigNames[2], int.class);
timeToLiveSecs = configurationService.getPropertyAsType(knownConfigNames[3], int.class);
timeToIdleSecs = configurationService.getPropertyAsType(knownConfigNames[4], int.class);
}
/**
* WARNING: Do not change the order of these! <br/>
* If you do, you have to fix the {@link #reloadConfig()} method -AZ
*/
private String[] knownConfigNames = {
"caching.use.clustering", // bool - whether to use clustering
"caching.default.use.disk.store", // whether to use the disk store
"caching.default.max.elements", // the maximum number of elements in memory, before they are evicted
"caching.default.time.to.live.secs", // the default amount of time to live for an element from its creation date
"caching.default.time.to.idle.secs", // the default amount of time to live for an element from its last accessed or modified date
};
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ConfigChangeListener#notifyForConfigNames()
*/
public String[] notifyForConfigNames() {
return knownConfigNames == null ? null : knownConfigNames.clone();
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ConfigChangeListener#configurationChanged(java.util.List, java.util.Map)
*/
public void configurationChanged(List<String> changedSettingNames, Map<String, String> changedSettings) {
reloadConfig();
}
/**
* This will make it easier to handle a provider which might go away because the classloader is gone
*/
private ProviderHolder<CacheProvider> provider = new ProviderHolder<CacheProvider>();
public CacheProvider getCacheProvider() {
return provider.getProvider();
}
private void reloadProvider() {
boolean current = (getCacheProvider() != null);
CacheProvider cacheProvider = serviceManager.getServiceByName(CacheProvider.class.getName(), CacheProvider.class);
provider.setProvider(cacheProvider);
if (cacheProvider != null) {
log.info("Cache Provider loaded: " + cacheProvider.getClass().getName());
} else {
if (current) {
log.info("Cache Provider unloaded");
}
}
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ServiceChangeListener#notifyForTypes()
*/
public Class<?>[] notifyForTypes() {
return new Class<?>[] { CacheProvider.class };
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ServiceChangeListener#serviceRegistered(java.lang.String, java.lang.Object, java.util.List)
*/
public void serviceRegistered(String serviceName, Object service, List<Class<?>> implementedTypes) {
provider.setProvider((CacheProvider) service);
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ServiceChangeListener#serviceUnregistered(java.lang.String, java.lang.Object)
*/
public void serviceUnregistered(String serviceName, Object service) {
provider.setProvider(null);
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.InitializedService#init()
*/
public void init() {
log.info("init()");
// get settings
reloadConfig();
// make sure we have a cache manager
if (cacheManager == null) {
// not injected so we need to create one
ClassLoader cl = Thread.currentThread().getContextClassLoader();
InputStream is = cl.getResourceAsStream(DEFAULT_CONFIG);
if (is == null) {
throw new IllegalStateException("Could not init the cache manager, no config file found as a resource in the classloader: " + DEFAULT_CONFIG);
}
cacheManager = new CacheManager(is);
}
// register the cache manager as an MBean
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ManagementService.registerMBeans(cacheManager, mbs, true, true, false, false);
// get all caches out of the cachemanager and load them into the cache list
List<Ehcache> ehcaches = getAllEhCaches(false);
for (Ehcache ehcache : ehcaches) {
EhcacheCache cache = new EhcacheCache(ehcache, null);
cacheRecord.put(cache.getName(), cache);
}
// load provider
reloadProvider();
log.info("Caching service initialized:\n" + getStatus(null));
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ShutdownService#shutdown()
*/
public void shutdown() {
log.info("destroy()");
// for some reason this causes lots of errors so not using it for now -AZ
//ehCacheManagementService.dispose();
try {
cacheRecord.clear();
} catch (RuntimeException e) {
// whatever
}
try {
getRequestMap().clear();
} catch (RuntimeException e) {
// whatever
}
try {
cacheManager.removalAll();
} catch (RuntimeException e) {
// whatever
}
cacheManager.shutdown();
}
/* (non-Javadoc)
* @see org.dspace.services.CachingService#destroyCache(java.lang.String)
*/
public void destroyCache(String cacheName) {
if (cacheName == null || "".equals(cacheName)) {
throw new IllegalArgumentException("cacheName cannot be null or empty string");
}
// handle provider first
if (getCacheProvider() != null) {
try {
getCacheProvider().destroyCache(cacheName);
} catch (Exception e) {
log.warn("Failure in provider ("+getCacheProvider()+"): " + e.getMessage());
}
}
EhcacheCache cache = cacheRecord.get(cacheName);
if (cache != null) {
cacheManager.removeCache(cacheName);
cacheRecord.remove(cacheName);
} else {
getRequestMap().remove(cacheName);
}
}
/* (non-Javadoc)
* @see org.dspace.services.CachingService#getCache(java.lang.String, org.dspace.services.model.CacheConfig)
*/
public Cache getCache(String cacheName, CacheConfig cacheConfig) {
if (cacheName == null || "".equals(cacheName)) {
throw new IllegalArgumentException("cacheName cannot be null or empty string");
}
// find the cache in the records if possible
Cache cache = this.cacheRecord.get(cacheName);
if (cache == null) {
cache = this.getRequestMap().get(cacheName);
}
// handle provider
if (getCacheProvider() != null) {
if (cache == null
&& cacheConfig != null
&& ! CacheScope.REQUEST.equals(cacheConfig.getCacheScope()) ) {
try {
cache = getCacheProvider().getCache(cacheName, cacheConfig);
} catch (Exception e) {
log.warn("Failure in provider ("+getCacheProvider()+"): " + e.getMessage());
}
}
}
// no cache found so make one
if (cache == null) {
// create the cache type based on the cache config
if (cacheConfig != null
&& CacheScope.REQUEST.equals(cacheConfig.getCacheScope()) ) {
cache = instantiateMapCache(cacheName, cacheConfig);
} else {
cache = instantiateEhCache(cacheName, cacheConfig);
}
}
return cache;
}
/* (non-Javadoc)
* @see org.dspace.services.CachingService#getCaches()
*/
public List<Cache> getCaches() {
List<Cache> caches = new ArrayList<Cache>(this.cacheRecord.values());
if (getCacheProvider() != null) {
try {
caches.addAll( getCacheProvider().getCaches() );
} catch (Exception e) {
log.warn("Failure in provider ("+getCacheProvider()+"): " + e.getMessage());
}
}
caches.addAll(this.getRequestMap().values());
Collections.sort(caches, new NameComparator());
return caches;
}
/* (non-Javadoc)
* @see org.dspace.services.CachingService#getStatus(java.lang.String)
*/
public String getStatus(String cacheName) {
final StringBuilder sb = new StringBuilder();
if (cacheName == null || "".equals(cacheName)) {
// add in overall memory stats
sb.append("** Memory report\n");
sb.append(" freeMemory: " + Runtime.getRuntime().freeMemory());
sb.append("\n");
sb.append(" totalMemory: " + Runtime.getRuntime().totalMemory());
sb.append("\n");
sb.append(" maxMemory: " + Runtime.getRuntime().maxMemory());
sb.append("\n");
// caches summary report
List<Cache> allCaches = getCaches();
sb.append("\n** Full report of all known caches ("+allCaches.size()+"):\n");
for (Cache cache : allCaches) {
sb.append(" * ");
sb.append(cache.toString());
sb.append("\n");
if (cache instanceof EhcacheCache) {
Ehcache ehcache = ((EhcacheCache)cache).getCache();
sb.append(generateCacheStats(ehcache));
sb.append("\n");
}
}
} else {
// report for a single cache
sb.append("\n** Report for cache ("+cacheName+"):\n");
Cache cache = this.cacheRecord.get(cacheName);
if (cache == null) {
cache = this.getRequestMap().get(cacheName);
}
if (cache == null) {
sb.append(" * Could not find cache by this name: " + cacheName);
} else {
sb.append(" * ");
sb.append(cache.toString());
sb.append("\n");
if (cache instanceof EhcacheCache) {
Ehcache ehcache = ((EhcacheCache)cache).getCache();
sb.append(generateCacheStats(ehcache));
sb.append("\n");
}
}
}
final String rv = sb.toString();
return rv;
}
/* (non-Javadoc)
* @see org.dspace.services.CachingService#resetCaches()
*/
public void resetCaches() {
log.debug("resetCaches()");
List<Cache> allCaches = getCaches();
for (Cache cache : allCaches) {
cache.clear();
}
if (getCacheProvider() != null) {
try {
getCacheProvider().resetCaches();
} catch (Exception e) {
log.warn("Failure in provider ("+getCacheProvider()+"): " + e.getMessage());
}
}
System.runFinalization(); // force the JVM to try to clean up any remaining objects
// DO NOT CALL System.gc() here or I will have you shot -AZ
log.info("doReset(): Memory Recovery to: " + Runtime.getRuntime().freeMemory());
}
/**
* Return all caches from the CacheManager
*
* @param sorted if true then sort by name
* @return the list of all known ehcaches
*/
protected List<Ehcache> getAllEhCaches(boolean sorted) {
log.debug("getAllCaches()");
final String[] cacheNames = cacheManager.getCacheNames();
if (sorted) {
Arrays.sort(cacheNames);
}
final List<Ehcache> caches = new ArrayList<Ehcache>(cacheNames.length);
for (String cacheName : cacheNames) {
caches.add(cacheManager.getEhcache(cacheName));
}
return caches;
}
/**
* Create an EhcacheCache (and the associated EhCache) using the supplied name (with default settings)
* or get the cache out of spring or the current configured cache <br/>
* This expects that the cacheRecord has already been checked and will not check it again <br/>
* Will proceed in this order:
* 1) Attempt to load a bean with the name of the cache
* 2) Attempt to load cache from caching system
* 3) Create a new cache by this name
* 4) Put the cache in the cache record
*
* @param cacheName the name of the cache
* @param cacheConfig the config for this cache
* @return a cache instance
*/
protected EhcacheCache instantiateEhCache(String cacheName, CacheConfig cacheConfig) {
if (log.isDebugEnabled())
log.debug("instantiateEhCache(String " + cacheName + ")");
if (cacheName == null || "".equals(cacheName)) {
throw new IllegalArgumentException("String cacheName must not be null or empty!");
}
// try to locate a named cache in the service manager
Ehcache ehcache = serviceManager.getServiceByName(cacheName, Ehcache.class);
// try to locate the cache in the cacheManager by name
if (ehcache == null) {
// if this cache name is created or already in use then we just get it
if (!cacheManager.cacheExists(cacheName)) {
// did not find the cache
if (cacheConfig == null) {
cacheManager.addCache(cacheName); // create a new cache using ehcache defaults
} else {
if (useClustering) {
// TODO
throw new UnsupportedOperationException("Still need to do this");
} else {
cacheManager.addCache(cacheName); // create a new cache using ehcache defaults
}
}
log.info("Created new Cache (from default settings): " + cacheName);
}
ehcache = cacheManager.getEhcache(cacheName);
}
// wrap the ehcache in the cache impl
EhcacheCache cache = new EhcacheCache(ehcache, cacheConfig);
cacheRecord.put(cacheName, cache);
return cache;
}
/**
* Create a thread map cache using the supplied name with supplied settings <br/>
* This expects that the cacheRecord has already been checked and will not check it again <br/>
* It also places the cache into the request map
*
* @param cacheName the name of the cache
* @param cacheConfig the config for this cache
* @return a cache instance
*/
protected MapCache instantiateMapCache(String cacheName, CacheConfig cacheConfig) {
if (log.isDebugEnabled())
log.debug("instantiateMapCache(String " + cacheName + ")");
if (cacheName == null || "".equals(cacheName)) {
throw new IllegalArgumentException("String cacheName must not be null or empty!");
}
// check for existing cache
MapCache cache = null;
CacheScope scope = CacheScope.REQUEST;
if (cacheConfig != null) {
scope = cacheConfig.getCacheScope();
}
if (CacheScope.REQUEST.equals(scope)) {
cache = getRequestMap().get(cacheName);
}
if (cache == null) {
cache = new MapCache(cacheName, cacheConfig);
// place cache into the right TL
if (CacheScope.REQUEST.equals(scope)) {
getRequestMap().put(cacheName, cache);
}
}
return cache;
}
/**
* Generate some stats for this cache,
* note that this is not cheap so do not use it very often
* @param cache an Ehcache
* @return the stats of this cache as a string
*/
protected static String generateCacheStats(Ehcache cache) {
StringBuilder sb = new StringBuilder();
sb.append(cache.getName() + ":");
// this will make this costly but it is important to get accurate settings
cache.setStatisticsAccuracy(Statistics.STATISTICS_ACCURACY_GUARANTEED);
Statistics stats = cache.getStatistics();
final long memSize = cache.getMemoryStoreSize();
final long diskSize = cache.getDiskStoreSize();
final long size = memSize + diskSize;
final long hits = stats.getCacheHits();
final long misses = stats.getCacheMisses();
final String hitPercentage = ((hits+misses) > 0) ? ((100l * hits) / (hits + misses)) + "%" : "N/A";
final String missPercentage = ((hits+misses) > 0) ? ((100l * misses) / (hits + misses)) + "%" : "N/A";
sb.append(" Size: " + size + " [memory:" + memSize + ", disk:" + diskSize + "]");
sb.append(", Hits: " + hits + " [memory:" + stats.getInMemoryHits() +
", disk:" + stats.getOnDiskHits() + "] (" + hitPercentage + ")");
sb.append(", Misses: " + misses + " (" + missPercentage + ")");
return sb.toString();
}
public static class NameComparator implements Comparator<Cache>, Serializable {
public final static long serialVersionUID = 1l;
public int compare(Cache o1, Cache o2) {
return o1.getName().compareTo(o2.getName());
}
}
}

View File

@@ -0,0 +1,34 @@
/**
* $Id: ThreadLocalMap.java 3310 2008-11-20 10:21:15Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/services/caching/ThreadLocalMap.java $
* ThreadLocalMap.java - DSpace2 - Oct 23, 2008 11:07:46 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.caching;
import java.util.HashMap;
import java.util.Map;
import org.dspace.services.caching.model.MapCache;
/**
* A simple threadlocal for holding maps of caches
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class ThreadLocalMap extends ThreadLocal<Map<String, MapCache>> {
@Override
protected Map<String, MapCache> initialValue() {
return new HashMap<String, MapCache>();
}
}

View File

@@ -0,0 +1,213 @@
/**
* $Id: EhcacheCache.java 3311 2008-11-20 12:15:14Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/services/caching/model/EhcacheCache.java $
* EhcacheCache.java - DSpace2 - Oct 23, 2008 11:26:12 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.caching.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.Status;
import org.dspace.services.model.Cache;
import org.dspace.services.model.CacheConfig;
import org.dspace.services.model.CacheConfig.CacheScope;
/**
* The ehcache implementation of the cache object
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class EhcacheCache implements Cache {
protected Ehcache cache;
public Ehcache getCache() {
return cache;
}
protected CacheConfig cacheConfig;
public EhcacheCache(Ehcache cache, CacheConfig cacheConfig) {
// setup the cache
if (cache == null) {
throw new NullPointerException("Cache must be set and cannot be null");
} else {
if (cache.getStatus() != Status.STATUS_ALIVE) {
throw new IllegalArgumentException("Cache ("+cache.getName()+") must already be initialized and alive");
}
}
this.cache = cache;
if (cacheConfig != null) {
this.cacheConfig = cacheConfig;
} else {
this.cacheConfig = new CacheConfig(CacheScope.INSTANCE);
}
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#getConfig()
*/
public CacheConfig getConfig() {
return cacheConfig;
}
/* (non-Javadoc)
* @see org.sakaiproject.caching.Cache#clear()
*/
public void clear() {
cache.removeAll();
cache.clearStatistics();
}
/* (non-Javadoc)
* @see org.sakaiproject.caching.Cache#exists(java.lang.String)
*/
public boolean exists(String key) {
if (key == null) {
throw new IllegalArgumentException("key cannot be null");
}
return cache.isKeyInCache(key);
}
/* (non-Javadoc)
* @see org.sakaiproject.caching.Cache#get(java.lang.String)
*/
public Object get(String key) {
if (key == null) {
throw new IllegalArgumentException("key cannot be null");
}
Serializable payload = (Serializable) getCachePayload(key, false);
return payload;
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#getKeys()
*/
public List<String> getKeys() {
ArrayList<String> keys = new ArrayList<String>();
List<?> eKeys = cache.getKeys();
for (Object object : eKeys) {
if (object != null) {
keys.add(object.toString());
}
}
return keys;
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#look(java.lang.String)
*/
public Object look(String key) {
if (key == null) {
throw new IllegalArgumentException("key cannot be null");
}
Serializable payload = (Serializable) getCachePayload(key, true);
return payload;
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#put(java.lang.String, java.io.Serializable)
*/
public void put(String key, Object value) {
if (key == null) {
throw new IllegalArgumentException("key cannot be null");
}
cache.put(new Element(key, value));
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#getName()
*/
public String getName() {
if (cache != null) {
return cache.getName();
} else {
return "NULL cache";
}
}
/* (non-Javadoc)
* @see org.sakaiproject.caching.Cache#remove(java.lang.String)
*/
public boolean remove(String key) {
if (key == null) {
throw new IllegalArgumentException("key cannot be null");
}
return cache.remove(key);
}
/* (non-Javadoc)
* @see org.sakaiproject.caching.Cache#size()
*/
public int size() {
return cache.getSize();
}
/**
* Retrieve a payload from the cache for this key if one can be found
* @param key the key for this cache element
* @return the payload or null if none found
*/
private Object getCachePayload(String key, boolean quiet) {
Object payload = null;
Element e;
if (quiet) {
e = cache.getQuiet(key);
} else {
e = cache.get(key);
}
if (e != null) {
// attempt to get the serialized value first
if (e.isSerializable()) {
payload = e.getValue();
} else {
// not serializable so get the object value
payload = e.getObjectValue();
}
}
return payload;
}
@Override
public boolean equals(Object obj) {
if (null == obj)
return false;
if (!(obj instanceof EhcacheCache))
return false;
else {
EhcacheCache castObj = (EhcacheCache) obj;
if (null == this.getName() || null == castObj.getName())
return false;
else
return (this.getName().equals(castObj.getName()));
}
}
@Override
public int hashCode() {
if (null == this.getName())
return super.hashCode();
String hashStr = this.getClass().getName() + ":" + this.getName().hashCode();
return hashStr.hashCode();
}
@Override
public String toString() {
return "EhCache:name="+getName()+":Scope="+cacheConfig.getCacheScope()+":size="+size();
}
}

View File

@@ -0,0 +1,143 @@
/**
* $Id: MapCache.java 3311 2008-11-20 12:15:14Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/services/caching/model/MapCache.java $
* MapCache.java - DSpace2 - Oct 23, 2008 11:40:59 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.caching.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.dspace.services.model.Cache;
import org.dspace.services.model.CacheConfig;
import org.dspace.services.model.CacheConfig.CacheScope;
/**
* This is a simple cache that just uses a map to store the cache values,
* used for the request and thread caches
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class MapCache implements Cache {
private HashMap<String, Object> cache;
public HashMap<String, Object> getCache() {
return cache;
}
protected String name;
protected CacheConfig cacheConfig;
public MapCache(String name, CacheConfig cacheConfig) {
if (name == null) {
throw new IllegalArgumentException("name cannot be null");
}
this.name = name;
this.cache = new HashMap<String, Object>();
if (cacheConfig != null) {
this.cacheConfig = cacheConfig;
} else {
this.cacheConfig = new CacheConfig(CacheScope.REQUEST);
}
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#clear()
*/
public void clear() {
this.cache.clear();
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#exists(java.lang.String)
*/
public boolean exists(String key) {
if (key == null) {
throw new IllegalArgumentException("key cannot be null");
}
return this.cache.containsKey(key);
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#get(java.lang.String)
*/
public Object get(String key) {
if (key == null) {
throw new IllegalArgumentException("key cannot be null");
}
return this.cache.get(key);
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#getKeys()
*/
public List<String> getKeys() {
ArrayList<String> keys = new ArrayList<String>(this.cache.keySet());
return keys;
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#getConfig()
*/
public CacheConfig getConfig() {
return this.cacheConfig;
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#getName()
*/
public String getName() {
return this.name;
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#look(java.lang.String)
*/
public Object look(String key) {
return get(key);
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#put(java.lang.String, java.io.Serializable)
*/
public void put(String key, Object value) {
if (key == null) {
throw new IllegalArgumentException("key cannot be null");
}
this.cache.put(key, value);
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#remove(java.lang.String)
*/
public boolean remove(String key) {
if (key == null) {
throw new IllegalArgumentException("key cannot be null");
}
return this.cache.remove(key) != null;
}
/* (non-Javadoc)
* @see org.dspace.services.model.Cache#size()
*/
public int size() {
return this.cache.size();
}
@Override
public String toString() {
return "MapCache:name="+getName()+":Scope="+cacheConfig.getCacheScope()+":size="+size();
}
}

View File

@@ -21,12 +21,22 @@ import java.util.Random;
import org.azeckoski.reflectutils.ArrayUtils;
import org.azeckoski.reflectutils.refmap.ReferenceMap;
import org.azeckoski.reflectutils.refmap.ReferenceType;
import org.dspace.kernel.mixins.ShutdownService;
import org.dspace.services.CachingService;
import org.dspace.services.EventService;
import org.dspace.services.RequestService;
import org.dspace.services.SessionService;
import org.dspace.services.model.Cache;
import org.dspace.services.model.CacheConfig;
import org.dspace.services.model.Event;
import org.dspace.services.model.EventListener;
import org.dspace.services.model.RequestInterceptor;
import org.dspace.services.model.Session;
import org.dspace.services.model.CacheConfig.CacheScope;
import org.dspace.services.model.Event.Scope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* This is a placeholder until we get a real event service going,
@@ -35,17 +45,49 @@ import org.slf4j.LoggerFactory;
*
* @author Aaron Zeckoski (azeckoski@gmail.com) - azeckoski - 4:02:31 PM Nov 19, 2008
*/
public class SystemEventService implements EventService {
public class SystemEventService implements EventService, ShutdownService {
private final Logger log = LoggerFactory.getLogger(SystemEventService.class);
private static final String QUEUE_CACHE_NAME = "eventQueueCache";
/**
* map for holding onto the listeners which is ClassLoader safe
*/
private ReferenceMap<String, EventListener> listenersMap = new ReferenceMap<String, EventListener>(ReferenceType.STRONG, ReferenceType.WEAK);
public SystemEventService(){
private final RequestService requestService;
private final SessionService sessionService;
private final CachingService cachingService;
private EventRequestInterceptor requestInterceptor;
private Cache queueCache;
@Autowired(required=true)
public SystemEventService(RequestService requestService, SessionService sessionService, CachingService cachingService) {
if (requestService == null || cachingService == null || sessionService == null) {
throw new IllegalArgumentException("requestService, cachingService, and all inputs must not be null");
}
this.requestService = requestService;
this.sessionService = sessionService;
this.cachingService = cachingService;
// create the cache
this.queueCache = this.cachingService.getCache(QUEUE_CACHE_NAME, new CacheConfig(CacheScope.REQUEST));
// register interceptor
this.requestInterceptor = new EventRequestInterceptor();
this.requestService.registerRequestInterceptor(this.requestInterceptor);
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ShutdownService#shutdown()
*/
public void shutdown() {
this.requestInterceptor = null; // clear the interceptor
this.listenersMap.clear();
this.queueCache.clear();
}
/* (non-Javadoc)
* @see org.dspace.services.EventService#fireEvent(org.dspace.services.model.Event)
@@ -73,10 +115,17 @@ public class SystemEventService implements EventService {
*/
public void queueEvent(Event event) {
validateEvent(event);
// put the event in the queue if this is in a request
if (requestService.getCurrentRequestId() != null) {
// create a key which is orderable and unique
String key = System.currentTimeMillis() + ":" + this.queueCache.size() + ":" + event.getId();
this.queueCache.put(key, event);
} else {
// no request so fire the event immediately
log.info("No request to queue this event ("+event+") so firing immediately");
fireEvent(event);
}
}
/* (non-Javadoc)
* @see org.dspace.services.EventService#registerEventListener(org.dspace.services.model.EventListener)
@@ -135,6 +184,37 @@ public class SystemEventService implements EventService {
log.warn("fireExternalEvent is not implemented yet, no support for external events yet, could not fire event to external listeners: " + event);
}
/**
* Fires all queued events for the current request
*
* @return the number of events which were fired
*/
protected int fireQueuedEvents() {
int fired = 0;
List<String> eventIds = this.queueCache.getKeys();
Collections.sort(eventIds); // put it in the order they were added (hopefully)
if (eventIds.size() > 0) {
for (String eventId : eventIds) {
Event event = (Event) this.queueCache.get(eventId);
fireEvent(event);
fired++;
}
}
this.queueCache.clear();
return fired;
}
/**
* Clears all events for the current request
*
* @return the number of events that were cleared
*/
protected int clearQueuedEvents() {
int cleared = this.queueCache.size();
this.queueCache.clear();
return cleared;
}
/**
* This will validate the event object and set any values which are unset but can be figured out
*
@@ -153,8 +233,8 @@ public class SystemEventService implements EventService {
}
if (event.getUserId() == null || "".equals(event.getUserId()) ) {
// set to the current user
//String userId = this.sessionService.getCurrentUserId();
//event.setUserId(userId);
String userId = this.sessionService.getCurrentUserId();
event.setUserId(userId);
}
if (event.getScopes() == null) {
// set to local/cluster scope
@@ -223,4 +303,41 @@ public class SystemEventService implements EventService {
return "event-" + random.nextInt(1000) + "-" + System.currentTimeMillis();
}
/**
* The request interceptor for the event service,
* this will take care of firing queued events at the end of the request
*
* @author Aaron Zeckoski (azeckoski@gmail.com) - azeckoski - 10:24:58 AM Nov 20, 2008
*/
public class EventRequestInterceptor implements RequestInterceptor {
/* (non-Javadoc)
* @see org.dspace.services.model.RequestInterceptor#onStart(java.lang.String, org.dspace.services.model.Session)
*/
public void onStart(String requestId, Session session) {
// nothing to really do here unless we decide we should purge out any existing events? -AZ
}
/* (non-Javadoc)
* @see org.dspace.services.model.RequestInterceptor#onEnd(java.lang.String, org.dspace.services.model.Session, boolean, java.lang.Exception)
*/
public void onEnd(String requestId, Session session, boolean succeeded, Exception failure) {
if (succeeded) {
int fired = fireQueuedEvents();
log.info("Fired "+fired+" events at the end of the request ("+requestId+")");
} else {
int cleared = clearQueuedEvents();
log.info("Cleared/cancelled "+cleared+" events at the end of the failed request ("+requestId+")");
}
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.OrderedService#getOrder()
*/
public int getOrder() {
return 20; // this should fire pretty late
}
}
}

View File

@@ -0,0 +1,428 @@
/**
* $Id: SessionRequestServiceImpl.java 3523 2009-03-05 14:58:10Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/services/sessions/SessionRequestServiceImpl.java $
* SessionServiceImpl.java - DSpace2 - Oct 28, 2008 10:08:51 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.sessions;
import org.azeckoski.reflectutils.refmap.ReferenceMap;
import org.azeckoski.reflectutils.refmap.ReferenceType;
import org.dspace.kernel.mixins.InitializedService;
import org.dspace.kernel.mixins.ShutdownService;
import org.dspace.services.CachingService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.RequestService;
import org.dspace.services.SessionService;
import org.dspace.services.model.Cache;
import org.dspace.services.model.CacheConfig;
import org.dspace.services.model.CacheConfig.CacheScope;
import org.dspace.services.model.RequestInterceptor;
import org.dspace.services.model.RequestInterceptor.RequestInterruptionException;
import org.dspace.services.model.Session;
import org.dspace.services.sessions.model.SessionImpl;
import org.dspace.utils.servicemanager.OrderedServiceComparator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Implementation of the session service <br/>
* This depends on having something (a filter typically) which is placing the current requests into
* a request storage cache <br/>
* TODO use a HttpSessionListener to keep track of all sessions?
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class SessionRequestServiceImpl implements SessionService, RequestService, InitializedService, ShutdownService {
private static Logger log = LoggerFactory.getLogger(SessionRequestServiceImpl.class);
public static final String REQUEST_ID_PREFIX = "request-";
private CachingService cachingService;
@Autowired
@Required
public void setCachingService(CachingService cachingService) {
this.cachingService = cachingService;
}
private ConfigurationService configurationService;
@Autowired
@Required
public void setConfigurationService(ConfigurationService configurationService) {
this.configurationService = configurationService;
}
/**
* map for holding onto the request interceptors which is classloader safe
*/
private ReferenceMap<String, RequestInterceptor> interceptorsMap = new ReferenceMap<String, RequestInterceptor>(ReferenceType.STRONG, ReferenceType.WEAK);
/**
* Keeps track of the sessions created by this service
*/
private ConcurrentHashMap<String, SessionImpl> sessions = new ConcurrentHashMap<String, SessionImpl>();
private ScheduledExecutorService expiryService = null;
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.InitializedService#init()
*/
public void init() {
log.info("init");
// start up the session expiring timer
expiryService = new ScheduledThreadPoolExecutor(1);
// start up the session expiry thread which runs every 5 minutes
long expiryInterval = configurationService.getPropertyAsType("session.expiry.interval", 300000l);
expiryService.scheduleAtFixedRate(new SessionCleanup(), expiryInterval, expiryInterval, TimeUnit.MILLISECONDS);
}
protected class SessionCleanup implements Runnable {
public void run() {
int expiredCount = 0;
for (Iterator<SessionImpl> iterator = sessions.values().iterator(); iterator.hasNext();) {
SessionImpl session = iterator.next();
if (session.isInvalidated()) {
// already invalidated so trash it
iterator.remove();
expiredCount++;
} else {
// time to invalidate it so do that and then trash it
long mii = session.getMaxInactiveInterval();
long lat = session.getLastAccessedTime();
long curInterval = System.currentTimeMillis() - lat;
if (curInterval > (mii * 1000l)) {
session.invalidate();
iterator.remove();
expiredCount++;
}
}
}
log.info("Expired "+expiredCount+" user sessions, "+sessions.size()+" sessions remain active");
}
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ShutdownService#shutdown()
*/
public void shutdown() {
log.info("shutdown");
clear();
// Cancel the Timer on shutdown
if (this.expiryService != null) {
List<Runnable> scheduledTasks = this.expiryService.shutdownNow();
if (scheduledTasks != null && scheduledTasks.size() > 0) {
log.info("Shutdown with " + scheduledTasks.size() + " tasks remaining");
}
}
}
/**
* clears out the settings inside this service,
* mostly for testing
*/
public void clear() {
// immediately clear all interceptors when the service is terminated
this.interceptorsMap.clear();
// also clear the entire copy of all running sessions when this shuts down
this.sessions.clear();
// flush the request cache
if (this.cachingService != null) {
this.cachingService.unbindRequestCaches();
}
}
/* (non-Javadoc)
* @see org.dspace.services.RequestService#startRequest()
*/
public String startRequest() {
// assure a session exists in the request cache before the request starts
Session session = makeSession(null);
// generate a requestId
String requestId = makeRequestId();
// call the list of interceptors
List<RequestInterceptor> interceptors = getInterceptors(false);
for (RequestInterceptor requestInterceptor : interceptors) {
if (requestInterceptor != null) {
try {
requestInterceptor.onStart(requestId, session);
} catch (RequestInterruptionException e) {
String message = "Request stopped from starting by exception from the interceptor ("+requestInterceptor+"): " + e.getMessage();
log.warn(message);
throw new RequestInterruptionException(message, e);
} catch (Exception e) {
log.warn("Request interceptor ("+requestInterceptor+") failed to execute on start ("+requestId+"): " + e.getMessage());
}
}
}
// put the id into the request cache
getRequestCache().put(CachingService.REQUEST_ID_KEY, requestId);
return requestId;
}
/* (non-Javadoc)
* @see org.dspace.services.RequestService#endRequest(java.lang.Exception)
*/
public String endRequest(Exception failure) {
String requestId = getCurrentRequestId();
if (requestId != null) {
try {
getRequestCache().remove(CachingService.REQUEST_ID_KEY);
// get session and execute the interceptors
Session session = getCurrentSession();
List<RequestInterceptor> interceptors = getInterceptors(true); // reverse
for (RequestInterceptor requestInterceptor : interceptors) {
if (requestInterceptor != null) {
try {
requestInterceptor.onEnd(requestId, session, (failure == null), failure);
} catch (RequestInterruptionException e) {
log.warn("Attempt to stop request from ending by an exception from the interceptor ("+requestInterceptor+"), cannot stop requests from ending though so request end continues, this may be an error: " + e.getMessage());
} catch (Exception e) {
log.warn("Request interceptor ("+requestInterceptor+") failed to execute on end ("+requestId+"): " + e.getMessage());
}
}
}
} finally {
// purge the request caches
cachingService.unbindRequestCaches();
}
} else {
// request not found, just log a warning
log.warn("Attempting to end a request when none currently exists");
}
return requestId;
}
private Random random = new Random();
/**
* @return a generated request Id used to identify and track this request
*/
private String makeRequestId() {
String requestId = REQUEST_ID_PREFIX + random.nextInt(1000) + "-" + System.currentTimeMillis();
Session session = getCurrentSession();
if (session != null) {
requestId += ":" + session.getId() + ":" + session.getUserId();
}
return requestId;
}
/**
* @return the current list of interceptors in the correct order
*/
private List<RequestInterceptor> getInterceptors(boolean reverse) {
ArrayList<RequestInterceptor> l = new ArrayList<RequestInterceptor>( this.interceptorsMap.values() );
OrderedServiceComparator comparator = new OrderedServiceComparator();
Collections.sort(l, comparator );
if (reverse) {
Collections.reverse(l);
}
return l;
}
/* (non-Javadoc)
* @see org.dspace.services.RequestService#registerRequestListener(org.dspace.services.model.RequestInterceptor)
*/
public void registerRequestInterceptor(RequestInterceptor interceptor) {
if (interceptor == null) {
throw new IllegalArgumentException("Cannot register an interceptor that is null");
}
if (interceptor.getOrder() <= 0) {
throw new IllegalArgumentException("Interceptor ordering for RequestInterceptor's must be greater than 0");
}
String key = interceptor.getOrder() + ":" + interceptor.getClass().getName();
this.interceptorsMap.put(key, interceptor);
}
/**
* Makes a session from the existing http session stuff in the current request or creates
* a new session of non-http related sessions
*
* @param sessionId an optional id to assign
* @return the new session object which is placed into the request
* @throws IllegalStateException if not session can be created
*/
public Session makeSession(String sessionId) {
SessionImpl sessionImpl = null;
Cache cache = getRequestCache();
if (sessionId == null) {
// gets the current session from the request if one exists
String curSessionId = getCurrentSessionId();
sessionImpl = getSessionImpl(curSessionId);
}
if (sessionImpl == null) {
// no session found yet so make one
HttpServletRequest httpRequest = (HttpServletRequest) cache.get(CachingService.HTTP_REQUEST_KEY);
if (httpRequest == null) {
// creates the session in a local storage
sessionImpl = new SessionImpl();
} else {
// create a session from the one in the request
sessionImpl = new SessionImpl(httpRequest);
}
if (sessionImpl.isIncomplete()) {
// set the required values on the session
sessionImpl.setSessionId(sessionId);
String serverId = configurationService.getProperty("server.id");
sessionImpl.setServerId(serverId);
int interval = configurationService.getPropertyAsType("session.max.inactive.interval", 3600);
sessionImpl.setMaxInactiveInterval(interval);
log.info("Created new session: " + sessionImpl);
}
// put the session in the request cache
cache.put(CachingService.SESSION_ID_KEY, sessionImpl.getId());
}
// track the session in the map (or refresh it)
sessions.put(sessionImpl.getSessionId(), sessionImpl); // sessions mapped by the sessionId and not the id
return sessionImpl;
}
/**
* Retrieves a session by the id if it is active
*
* @param sessionId the unique id for a session
* @return a session if one is available OR null if none found
* @throws IllegalArgumentException if the sessionId is null
*/
public Session getSession(String sessionId) {
return getSessionImpl(sessionId);
}
/**
* INTERNAL USE
* Same as getSession but retrieves the implementation
*/
private SessionImpl getSessionImpl(String sessionId) {
SessionImpl session = null;
if (sessionId != null) {
session = sessions.get(sessionId);
if (session != null) {
if (session.isInvalidated()) {
sessions.remove(sessionId);
session = null;
}
}
}
return session;
}
/**
* Get the list of sessions,
* this will automatically purge out any sessions which have expired
* @return the list of all active sessions ordered by last time accessed
*/
public List<Session> getAllActiveSessions() {
ArrayList<Session> l = new ArrayList<Session>();
for (Iterator<SessionImpl> iterator = sessions.values().iterator(); iterator.hasNext();) {
SessionImpl session = iterator.next();
if (session.isInvalidated()) {
iterator.remove();
} else {
l.add(session);
}
}
Collections.sort(l, new SessionImpl.SessionLastAccessedComparator());
return l;
}
/* (non-Javadoc)
* @see org.dspace.services.SessionService#bindSession(java.lang.String, java.lang.String, java.lang.String)
*/
public Session bindSession(String sessionId, String userId, String userEid) {
if (sessionId == null) {
throw new IllegalArgumentException("sessionId cannot be null");
}
SessionImpl session = getSessionImpl(sessionId);
if (session == null) {
throw new IllegalArgumentException("Could not find a session with the id: " + sessionId);
} else {
if (userId != null) {
if (userEid == null || "".equals(userEid)) {
throw new IllegalArgumentException("userEid must be set when userId is set or cannot bind the session");
}
session.setUserId(userId, userEid);
} else {
session.setUserId(null, null);
}
}
return session;
}
/* (non-Javadoc)
* @see org.dspace.services.SessionService#startSession(java.lang.String)
*/
public Session startSession(String sessionId) {
return makeSession(sessionId);
}
/* (non-Javadoc)
* @see org.dspace.services.SessionService#getCurrentSession()
*/
public Session getCurrentSession() {
String sessionId = getCurrentSessionId();
Session session = getSessionImpl(sessionId);
return session;
}
/* (non-Javadoc)
* @see org.dspace.services.SessionService#getCurrentSessionId()
*/
public String getCurrentSessionId() {
String sessionId = (String) getRequestCache().get(CachingService.SESSION_ID_KEY);
return sessionId;
}
/* (non-Javadoc)
* @see org.dspace.services.SessionService#getCurrentUserId()
*/
public String getCurrentUserId() {
String userId = null;
Session session = getCurrentSession();
if (session != null) {
userId = session.getUserId();
}
return userId;
}
/* (non-Javadoc)
* @see org.dspace.services.RequestService#getCurrentRequestId()
*/
public String getCurrentRequestId() {
String requestId = (String) getRequestCache().get(CachingService.REQUEST_ID_KEY);
return requestId;
}
/**
* @return the request storage cache
*/
private Cache getRequestCache() {
Cache cache = cachingService.getCache(CachingService.REQUEST_CACHE, new CacheConfig(CacheScope.REQUEST));
return cache;
}
}

View File

@@ -0,0 +1,205 @@
/**
* $Id: InternalHttpSession.java 3254 2008-10-30 12:17:38Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/services/sessions/model/InternalHttpSession.java $
* InternalHttpSession.java - DSpace2 - Oct 29, 2008 4:11:27 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.sessions.model;
import java.util.Enumeration;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;
/**
* This is a special http session object that stands in for a real one when sessions are
* not initiated or associated by http requests
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
@SuppressWarnings("deprecation")
public class InternalHttpSession implements HttpSession {
private final String id;
private long lastAccessedTime = System.currentTimeMillis();
private long creationTime = System.currentTimeMillis();
private int maxInactiveInternal = 1800;
private boolean invalidated = false;
private ConcurrentHashMap<String, Object> attributes = null;
private ConcurrentHashMap<String, Object> getAttributes() {
if (this.attributes == null) {
this.attributes = new ConcurrentHashMap<String, Object>();
}
return this.attributes;
}
public InternalHttpSession() {
this.id = UUID.randomUUID().toString();
}
private void checkInvalidated() {
if (invalidated) {
throw new IllegalStateException("This session is no longer valid");
}
}
@Override
public String toString() {
return "internalSession:" + this.id + ":" + this.creationTime + ":" + this.invalidated + ":" + super.toString();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getAttribute(java.lang.String)
*/
public Object getAttribute(String name) {
checkInvalidated();
return getAttributes().get(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getAttributeNames()
*/
@SuppressWarnings("unchecked")
public Enumeration getAttributeNames() {
checkInvalidated();
return getAttributes().keys();
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getCreationTime()
*/
public long getCreationTime() {
checkInvalidated();
return creationTime;
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getId()
*/
public String getId() {
checkInvalidated();
return id;
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getLastAccessedTime()
*/
public long getLastAccessedTime() {
checkInvalidated();
return lastAccessedTime;
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getMaxInactiveInterval()
*/
public int getMaxInactiveInterval() {
checkInvalidated();
return maxInactiveInternal;
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getServletContext()
*/
public ServletContext getServletContext() {
checkInvalidated();
return null;
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getSessionContext()
*/
public HttpSessionContext getSessionContext() {
checkInvalidated();
return null;
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getValue(java.lang.String)
*/
public Object getValue(String name) {
checkInvalidated();
return getAttributes().get(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getValueNames()
*/
public String[] getValueNames() {
checkInvalidated();
Set<String> names = getAttributes().keySet();
return names.toArray(new String[names.size()]);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#invalidate()
*/
public void invalidate() {
invalidated = true;
if (this.attributes != null) {
this.attributes.clear();
this.attributes = null;
}
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#isNew()
*/
public boolean isNew() {
return false;
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#putValue(java.lang.String, java.lang.Object)
*/
public void putValue(String name, Object value) {
checkInvalidated();
getAttributes().put(name, value);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#removeAttribute(java.lang.String)
*/
public void removeAttribute(String name) {
checkInvalidated();
getAttributes().remove(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#removeValue(java.lang.String)
*/
public void removeValue(String name) {
checkInvalidated();
getAttributes().remove(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#setAttribute(java.lang.String, java.lang.Object)
*/
public void setAttribute(String name, Object value) {
checkInvalidated();
getAttributes().put(name, value);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#setMaxInactiveInterval(int)
*/
public void setMaxInactiveInterval(int interval) {
checkInvalidated();
this.maxInactiveInternal = interval;
}
}

View File

@@ -0,0 +1,480 @@
/**
* $Id: SessionImpl.java 3254 2008-10-30 12:17:38Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/main/java/org/dspace/services/sessions/model/SessionImpl.java $
* Session.java - DSpace2 - Oct 14, 2008 11:46:22 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.sessions.model;
import java.io.Serializable;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;
import org.dspace.services.model.Session;
/**
* Represents a users session (login session) in the system, can hold some additional attributes as
* needed but the underlying implementation may limit the number and size of attributes to ensure
* session replication is not impacted negatively
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
@SuppressWarnings("deprecation")
public class SessionImpl implements Session {
// keys for things stored in the session
public static final String SESSION_ID = "dspaceSessionId";
public static final String USER_ID = "userId";
public static final String USER_EID = "userEid";
public static final String SERVER_ID = "serverId";
public static final String HOST_IP = "originatingHostIP";
public static final String HOST_NAME = "originatingHostName";
/**
* this is the only thing that is actually replicated across the cluster
*/
private transient HttpSession httpSession;
/**
* Make a session that is associated with the current http request
* @param request
*/
public SessionImpl(HttpServletRequest request) {
if (request == null) {
throw new IllegalArgumentException("Cannot create a session without an http request");
}
this.httpSession = request.getSession(); // establish the session
setKeyAttribute(HOST_IP, request.getRemoteAddr());
setKeyAttribute(HOST_NAME, request.getRemoteHost());
}
/**
* Make a session which is not associated with the current http request
*/
public SessionImpl() {
// creates a new internal http session that is not cached anywhere
this.httpSession = new InternalHttpSession();
try {
InetAddress i4 = Inet4Address.getLocalHost();
setKeyAttribute(HOST_IP, i4.getHostAddress()); // IP address
setKeyAttribute(HOST_NAME, i4.getHostName());
} catch (UnknownHostException e) {
// could not get address
setKeyAttribute(HOST_IP, "10.0.0.1"); // set a fake one I guess
}
}
/**
* Set the sessionId, normally this should not probably happen much
* @param sessionId
*/
public void setSessionId(String sessionId) {
if (! isAttributeSet(SESSION_ID)) {
if (isBlank(sessionId)) {
// just use the http session id
sessionId = this.httpSession.getId();
}
setKeyAttribute(SESSION_ID, sessionId);
}
}
/**
* Set the userId and userEid, this should only happen when re-binding the session
* or clearing the associated user, if userId is null then user is cleared
* @param userId
* @param userEid
*/
public void setUserId(String userId, String userEid) {
if (isBlank(userId)) {
removeKeyAttribute(USER_ID);
removeKeyAttribute(USER_EID);
} else {
setKeyAttribute(USER_ID, userId);
setKeyAttribute(USER_EID, userEid);
}
}
/**
* Set the DSpace serverId which originated this session
* @param serverId the serverId
*/
public void setServerId(String serverId) {
setKeyAttribute(SERVER_ID, serverId);
}
/**
* @return true if this session already has all the required values needed to complete it,
* this means the serverId and other values in the session are already set
*/
public boolean isIncomplete() {
boolean complete = false;
if (isAttributeSet(SERVER_ID)
&& isAttributeSet(SESSION_ID)
&& isAttributeSet(HOST_IP)) {
complete = true;
}
return ! complete;
}
/**
* @param key the attribute key
* @return true if the attribute is set
*/
public boolean isAttributeSet(String key) {
return getKeyAtribute(key) != null;
}
/**
* @return true if this session is invalidated
*/
public boolean isInvalidated() {
boolean invalid = true;
if (this.httpSession != null) {
try {
this.httpSession.getCreationTime();
invalid = false;
} catch (IllegalStateException e) {
invalid = true;
}
} else {
// no httpsession
invalid = false;
}
return invalid;
}
/**
* Handles the general setting of things in the session,
* use this to build other set methods,
* handles checking the session is still valid and handles
* the checking for null values in the value and key
* @param key the key to use
* @param value the value to set
* @return true if the value was set, false if cleared or failure
* @throws IllegalArgumentException if the key is null
*/
protected boolean setKeyAttribute(String key, String value) {
if (key == null) {
throw new IllegalArgumentException("session attribute key cannot be null");
}
boolean wasSet = false;
if (! isInvalidated()) {
if (isBlank(value)) {
this.httpSession.removeAttribute(key);
} else {
this.httpSession.setAttribute(key, value);
wasSet = true;
}
}
return wasSet;
}
/**
* Handles the general getting of things from the session,
* use this to build other set methods,
* checks the session is still valid
* @param key the key to use
* @return the value OR null if not found
* @throws IllegalArgumentException if the key is null
*/
protected String getKeyAtribute(String key) {
if (key == null) {
throw new IllegalArgumentException("session attribute key cannot be null");
}
String value = null;
if (! isInvalidated()) {
value = (String) this.httpSession.getAttribute(key);
}
return value;
}
/**
* Handles removal of attributes and related checks
* @param key the key to use
* @throws IllegalArgumentException if the key is null
*/
protected void removeKeyAttribute(String key) {
if (key == null) {
throw new IllegalArgumentException("session attribute key cannot be null");
}
if (! isInvalidated()) {
this.httpSession.removeAttribute(key);
}
}
@Override
public boolean equals(Object obj) {
// sessions are equal if the ids are the same, allows comparison across reloaded items
if (null == obj)
return false;
if (!(obj instanceof SessionImpl))
return false;
else {
SessionImpl castObj = (SessionImpl) obj;
boolean eq;
try {
eq = this.getId().equals(castObj.getId());
} catch (IllegalStateException e) {
eq = false;
}
return eq;
}
}
@Override
public int hashCode() {
String hashStr = this.getClass().getName() + ":" + this.httpSession.toString();
return hashStr.hashCode();
}
@Override
public String toString() {
String str;
if (isInvalidated()) {
str = "invalidated:" + this.httpSession.toString() + ":" + super.toString();
} else {
str = "active:"+getId()+":user="+getUserId()+"("+getUserEID()+"):sid="+getSessionId()+":server="+getServerId()+":created="+getCreationTime()+":accessed="+getLastAccessedTime()+":maxInactiveSecs="+getMaxInactiveInterval()+":hostIP="+getOriginatingHostIP()+":hostName="+getOriginatingHostName()+":"+super.toString();
}
return "Session:" + str;
}
// INTERFACE methods
/* (non-Javadoc)
* @see org.dspace.services.model.Session#getAttribute(java.lang.String)
*/
public String getAttribute(String key) {
String attribute = getKeyAtribute(key);
return attribute;
}
/* (non-Javadoc)
* @see org.dspace.services.model.Session#setAttribute(java.lang.String, java.lang.String)
*/
public void setAttribute(String key, String value) {
setKeyAttribute(key, value);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#removeAttribute(java.lang.String)
*/
public void removeAttribute(String name) {
removeKeyAttribute(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#setAttribute(java.lang.String, java.lang.Object)
*/
public void setAttribute(String name, Object value) {
if (value != null && !(value instanceof String)) {
throw new UnsupportedOperationException("Invalid session attribute ("+name+","+value+"), Only strings can be stored in the session");
}
setKeyAttribute(name, (String) value);
}
/**
* @return a copy of the attributes in this session,
* modifying it has no effect on the session attributes
*/
@SuppressWarnings("unchecked")
public Map<String, String> getAttributes() {
Map<String, String> map = new HashMap<String, String>();
if (! isInvalidated()) {
Enumeration<String> names = this.httpSession.getAttributeNames();
while (names.hasMoreElements()) {
String key = names.nextElement();
String value = (String) this.httpSession.getAttribute(key);
map.put(key, value);
}
}
return map;
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getAttributeNames()
*/
@SuppressWarnings("unchecked")
public Enumeration getAttributeNames() {
return this.httpSession.getAttributeNames();
}
/* (non-Javadoc)
* @see org.dspace.services.model.Session#clear()
*/
@SuppressWarnings("unchecked")
public void clear() {
if (! isInvalidated()) {
Enumeration<String> names = this.httpSession.getAttributeNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
this.httpSession.removeAttribute(name);
}
}
}
public String getOriginatingHostIP() {
return getKeyAtribute(HOST_IP);
}
public String getOriginatingHostName() {
return getKeyAtribute(HOST_NAME);
}
public String getServerId() {
return getKeyAtribute(SERVER_ID);
}
public String getSessionId() {
return getKeyAtribute(SESSION_ID);
}
public String getUserEID() {
return getKeyAtribute(USER_EID);
}
public String getUserId() {
return getKeyAtribute(USER_ID);
}
public boolean isActive() {
return ! isInvalidated();
}
// HTTP SESSION passthroughs
public long getCreationTime() {
return this.httpSession.getCreationTime();
}
public String getId() {
String id = null;
if (isAttributeSet(SESSION_ID)) {
id = getKeyAtribute(SESSION_ID);
} else {
id = this.httpSession.getId();
}
return id;
}
public long getLastAccessedTime() {
return this.httpSession.getLastAccessedTime();
}
public int getMaxInactiveInterval() {
return this.httpSession.getMaxInactiveInterval();
}
public void setMaxInactiveInterval(int interval) {
this.httpSession.setMaxInactiveInterval(interval);
}
public ServletContext getServletContext() {
if (this.httpSession != null) {
return this.httpSession.getServletContext();
}
throw new UnsupportedOperationException("No http session available for this operation");
}
public void invalidate() {
if (! isInvalidated()) {
this.httpSession.invalidate();
}
// TODO nothing otherwise?
}
public boolean isNew() {
if (! isInvalidated()) {
return this.httpSession.isNew();
}
return false;
}
// DEPRECATED
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getValue(java.lang.String)
*/
public Object getValue(String name) {
return getKeyAtribute(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#getValueNames()
*/
public String[] getValueNames() {
Set<String> keys = getAttributes().keySet();
return keys.toArray(new String[keys.size()]);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#removeValue(java.lang.String)
*/
public void removeValue(String name) {
removeAttribute(name);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSession#putValue(java.lang.String, java.lang.Object)
*/
public void putValue(String name, Object value) {
setAttribute(name, value);
}
public HttpSessionContext getSessionContext() {
if (this.httpSession != null) {
return this.httpSession.getSessionContext();
}
throw new UnsupportedOperationException("No http session available for this operation");
}
// END DEPRECATED
/**
* Check if something is blank (null or "")
* @param string
* @return true if is blank
*/
public static boolean isBlank(String string) {
return (string == null) || ("".equals(string));
}
/**
* Compares sessions by the last time they were accessed with more recent first
*/
public static class SessionLastAccessedComparator implements Comparator<Session>, Serializable {
public final static long serialVersionUID = 1l;
public int compare(Session o1, Session o2) {
try {
Long lat1 = Long.valueOf(o1.getLastAccessedTime());
Long lat2 = Long.valueOf(o2.getLastAccessedTime());
return lat2.compareTo(lat1); // reverse
} catch (Exception e) {
return 0;
}
}
}
}

View File

@@ -0,0 +1,515 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd">
<!-- Sets the path to the directory where cache .data files are created.
If the path is a Java System Property it is replaced by
its value in the running VM.
The following properties are translated:
user.home - User's home directory
user.dir - User's current working directory
java.io.tmpdir - Default temp file path -->
<diskStore path="java.io.tmpdir"/>
<!--
Cache configuration
===================
The following attributes are required.
name:
Sets the name of the cache. This is used to identify the cache. It must be unique.
maxElementsInMemory:
Sets the maximum number of objects that will be created in memory
maxElementsOnDisk:
Sets the maximum number of objects that will be maintained in the DiskStore
The default value is zero, meaning unlimited.
eternal:
Sets whether elements are eternal. If eternal, timeouts are ignored and the
element is never expired.
overflowToDisk:
Sets whether elements can overflow to disk when the memory store
has reached the maxInMemory limit.
The following attributes and elements are optional.
timeToIdleSeconds:
Sets the time to idle for an element before it expires.
i.e. The maximum amount of time between accesses before an element expires
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can idle for infinity.
The default value is 0.
timeToLiveSeconds:
Sets the time to live for an element before it expires.
i.e. The maximum time between creation time and when an element expires.
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that and Element can live for infinity.
The default value is 0.
diskPersistent:
Whether the disk store persists between restarts of the Virtual Machine.
The default value is false.
diskExpiryThreadIntervalSeconds:
The number of seconds between runs of the disk expiry thread. The default value
is 120 seconds.
diskSpoolBufferSizeMB:
This is the size to allocate the DiskStore for a spool buffer. Writes are made
to this area and then asynchronously written to disk. The default size is 30MB.
Each spool buffer is used only by its cache. If you get OutOfMemory errors consider
lowering this value. To improve DiskStore performance consider increasing it. Trace level
logging in the DiskStore will show if put back ups are occurring.
memoryStoreEvictionPolicy:
Policy would be enforced upon reaching the maxElementsInMemory limit. Default
policy is Least Recently Used (specified as LRU). Other policies available -
First In First Out (specified as FIFO) and Less Frequently Used
(specified as LFU)
*NOTE: LFU seems to have some possible issues -AZ
Cache elements can also contain sub elements which take the same format of a factory class
and properties. Defined sub-elements are:
* cacheEventListenerFactory - Enables registration of listeners for cache events, such as
put, remove, update, and expire.
* bootstrapCacheLoaderFactory - Specifies a BootstrapCacheLoader, which is called by a
cache on initialisation to prepopulate itself.
* cacheExtensionFactory - Specifies a CacheExtension, a generic mechansim to tie a class
which holds a reference to a cache to the cache lifecycle.
RMI Cache Replication
Each cache that will be distributed needs to set a cache event listener which replicates
messages to the other CacheManager peers. For the built-in RMI implementation this is done
by adding a cacheEventListenerFactory element of type RMICacheReplicatorFactory to each
distributed cache's configuration as per the following example:
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true
asynchronousReplicationIntervalMillis=<number of milliseconds"
propertySeparator="," />
The RMICacheReplicatorFactory recognises the following properties:
* replicatePuts=true|false - whether new elements placed in a cache are
replicated to others. Defaults to true.
* replicateUpdates=true|false - whether new elements which override an
element already existing with the same key are replicated. Defaults to true.
* replicateRemovals=true - whether element removals are replicated. Defaults to true.
* replicateAsynchronously=true | false - whether replications are
asynchronous (true) or synchronous (false). Defaults to true.
* replicateUpdatesViaCopy=true | false - whether the new elements are
copied to other caches (true), or whether a remove message is sent. Defaults to true.
* asynchronousReplicationIntervalMillis=<number of milliseconds> - The asynchronous
replicator runs at a set interval of milliseconds. The default is 1000. The minimum
is 10. This property is only applicable if replicateAsynchronously=true
Cluster Bootstrapping
The RMIBootstrapCacheLoader bootstraps caches in clusters where RMICacheReplicators are
used. It is configured as per the following example:
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"
propertySeparator="," />
The RMIBootstrapCacheLoaderFactory recognises the following optional properties:
* bootstrapAsynchronously=true|false - whether the bootstrap happens in the background
after the cache has started. If false, bootstrapping must complete before the cache is
made available. The default value is true.
* maximumChunkSizeBytes=<integer> - Caches can potentially be very large, larger than the
memory limits of the VM. This property allows the bootstraper to fetched elements in
chunks. The default chunk size is 5000000 (5MB).
Cache Exception Handling
By default, most cache operations will propagate a runtime CacheException on failure. An interceptor,
using a dynamic proxy, may be configured so that a CacheExceptionHandler can be configured to
intercept Exceptions. Errors are not intercepted. It is configured as per the following example:
<cacheExceptionHandlerFactory class="net.sf.ehcache.exceptionhandler.CountingExceptionHandlerFactory"
properties="logLevel=FINE"/>
Caches with ExceptionHandling configured are not of type Cache, but are of type Ehcache only, and are not available
using CacheManager.getCache(), but using CacheManager.getEhcache().
CacheLoader
A CacheLoader may be configured against a cache.
<cacheLoaderFactory class="net.sf.ehcache.loader.CountingCacheLoaderFactory"
properties="type=int,startCounter=10"/>
-->
<!--
Mandatory Default Cache configuration. These settings will be applied to caches
created programmtically using CacheManager.add(String cacheName).
The defaultCache has an implicit name "default" which is a reserved cache name.
-->
<defaultCache
maxElementsInMemory="3000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="1200"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
<!--Predefined caches. Add your cache configuration settings here.
If you do not have a configuration for your cache a WARNING will be issued when the
CacheManager starts
The following attributes are required for defaultCache:
name - Sets the name of the cache. This is used to identify the cache. It must be unique.
maxInMemory - Sets the maximum number of objects that will be created in memory
eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element
is never expired.
timeToIdleSeconds - Sets the time to idle for an element before it expires.
i.e. The maximum amount of time between accesses before an element expires
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can idle for infinity
timeToLiveSeconds - Sets the time to live for an element before it expires.
i.e. The maximum time between creation time and when an element expires.
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can live for infinity
overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
has reached the maxInMemory limit.
-->
<!-- CACHES FOR TESTING -->
<!--
<cache name="org.dspace.caching.MemOnly"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="1200"
overflowToDisk="false"
diskSpoolBufferSizeMB="0"
maxElementsOnDisk="0"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</cache>
<cache name="org.dspace.caching.DiskOnly"
maxElementsInMemory="1"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="1200"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</cache>
<cache name="org.dspace.caching.Distributed"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="10"
timeToLiveSeconds="30"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=false,
replicateRemovals=true "/>
</cache>
<cache name="org.dspace.caching.DistributedDisk"
maxElementsInMemory="5"
eternal="false"
timeToIdleSeconds="10"
timeToLiveSeconds="30"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=false,
replicateRemovals=true "/>
</cache>
-->
<!-- Place configuration for your caches following -->
<!-- this cache tracks the timestamps of the most recent updates to particular tables.
It is important that the cache timeout of the underlying cache implementation be set to a
higher value than the timeouts of any of the query caches. In fact, it is recommended that
the the underlying cache not be configured for expiry at all. -->
<!-- <cache name="org.hibernate.cache.UpdateTimestampsCache"-->
<!-- maxElementsInMemory="6000"-->
<!-- eternal="true"-->
<!-- overflowToDisk="false" />-->
<!-- this cache stores the actual objects pulled out of the DB by hibernate -->
<!-- <cache name="org.hibernate.cache.StandardQueryCache"-->
<!-- maxElementsInMemory="12000"-->
<!-- eternal="false"-->
<!-- timeToIdleSeconds="600"-->
<!-- timeToLiveSeconds="1200"-->
<!-- overflowToDisk="false" />-->
<!-- DISTRIBUTED CACHING
Add cacheEventListenerFactory to the cache
==========================================
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=false,
replicateRemovals=true "/>
For Example:
============
<cache name="org.dspace.authz.api.SecurityService.cache"
maxElementsInMemory="20000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="2400"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="100000"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="120">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=false,
replicateRemovals=true "/>
</cache>
CacheManagerPeerProvider
========================
(Enable for distributed operation)
Specifies a CacheManagerPeerProviderFactory which will be used to create a
CacheManagerPeerProvider, which discovers other CacheManagers in the cluster.
The attributes of cacheManagerPeerProviderFactory are:
* class - a fully qualified factory class name
* properties - comma separated properties having meaning only to the factory.
Ehcache comes with a built-in RMI-based distribution system with two means of discovery of
CacheManager peers participating in the cluster:
* automatic, using a multicast group. This one automatically discovers peers and detects
changes such as peers entering and leaving the group
* manual, using manual rmiURL configuration. A hardcoded list of peers is provided at
configuration time.
Configuring Automatic Discovery:
Automatic discovery is configured as per the following example:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=32"/>
Valid properties are:
* peerDiscovery (mandatory) - specify "automatic"
* multicastGroupAddress (mandatory) - specify a valid multicast group address
* multicastGroupPort (mandatory) - specify a dedicated port for the multicast heartbeat
traffic
* timeToLive - specify a value between 0 and 255 which determines how far the packets will propagate.
By convention, the restrictions are:
0 - the same host
1 - the same subnet
32 - the same site
64 - the same region
128 - the same continent
255 - unrestricted
Configuring Manual Discovery:
Manual discovery is configured as per the following example:
<cacheManagerPeerProviderFactory class=
"net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40000/sampleCache1|//server2:40000/sampleCache1
| //server1:40000/sampleCache2|//server2:40000/sampleCache2"
propertySeparator="," />
Valid properties are:
* peerDiscovery (mandatory) - specify "manual"
* rmiUrls (mandatory) - specify a pipe separated list of rmiUrls, in the form
//hostname:port
The hostname is the hostname of the remote CacheManager peer. The port is the listening
port of the RMICacheManagerPeerListener of the remote CacheManager peer.
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic,
multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=1"
propertySeparator=","
/>
-->
<!--
CacheManagerPeerListener
========================
(Enable for distributed operation)
Specifies a CacheManagerPeerListenerFactory which will be used to create a
CacheManagerPeerListener, which
listens for messages from cache replicators participating in the cluster.
The attributes of cacheManagerPeerListenerFactory are:
class - a fully qualified factory class name
properties - comma separated properties having meaning only to the factory.
Ehcache comes with a built-in RMI-based distribution system. The listener component is
RMICacheManagerPeerListener which is configured using
RMICacheManagerPeerListenerFactory. It is configured as per the following example:
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=fully_qualified_hostname_or_ip,
port=40001,
socketTimeoutMillis=120000"
propertySeparator="," />
All properties are optional. They are:
* hostName - the hostName of the host the listener is running on. Specify
where the host is multihomed and you want to control the interface over which cluster
messages are received. Defaults to the host name of the default interface if not
specified.
* port - the port the listener listens on. This defaults to a free port if not specified.
* socketTimeoutMillis - the number of ms client sockets will stay open when sending
messages to the listener. This should be long enough for the slowest message.
If not specified it defaults 120000ms.
* timeToLive - You can control how far the multicast packets propagate by setting the
badly misnamed time to live. Using the multicast IP protocol, the timeToLive value
indicates the scope or range in which a packet may be forwarded. By convention:
0 is restricted to the same host
1 is restricted to the same subnet
32 is restricted to the same site
64 is restricted to the same region
128 is restricted to the same continent
255 is unrestricted
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
-->
<!-- Sample Distributed cache settings -->
<!-- automatic discovery using tcp multicast
For the multicast version, the IP address is no longer that of the server.
Rather, you need to choose the address and port in a designated range that has been reserved for multicasting.
It is as if the server and all potential clients are agreeing that messages will be left in a particular location.
The available addresses for multicasting are in the range 224.0.0.0 through 239.255.255.255.
You can check for the assigned addresses in this range (http://www.iana.org/assignments/multicast-addresses).
Recommended default is to use the IP address 230.0.0.1 and the port 4446.
-->
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic,
multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446,
timeToLive=1" />
<!-- manual discovery (you must customize this to include every node in the cluster) -->
<!-- <cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server2:40001/sampleCache11|//server2:40001/sampleCache12" />
-->
<!--
A CacheManagerPeerListener listens for messages from peers to the current CacheManager.
You configure the CacheManagerPeerListener by specifiying a CacheManagerPeerListenerFactory which is used to create
the CacheManagerPeerListener using the plugin mechanism.
The attributes of cacheManagerPeerListenerFactory are:
* class - a fully qualified factory class name
* properties - comma separated properties having meaning only to the factory.
Ehcache comes with a built-in RMI-based distribution system. The listener component is RMICacheManagerPeerListener
which is configured using RMICacheManagerPeerListenerFactory. It is configured as per the following example:
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=localhost, port=40001, socketTimeoutMillis=2000" />
Valid properties are:
* hostName (optional) - the hostName of the host the listener is running on. Specify where the host is
multihomed and you want to control the interface over which cluster messages are received.
The hostname is checked for reachability during CacheManager initialisation.
If the hostName is unreachable, the CacheManager will refuse to start and an CacheException will be thrown
indicating connection was refused.
If unspecified, the hostname will use InetAddress.getLocalHost().getHostAddress(), which corresponds to the
default host network interface.
Warning: Explicitly setting this to localhost refers to the local loopback of 127.0.0.1, which is not network
visible and will cause no replications to be received from remote hosts. You should only use this setting when
multiple CacheManagers are on the same machine.
NOTE: this is not obvious, but if you run a netstat -an | grep LISTEN you will see that the configuration shown below:
properties="hostName=127.0.0.1, port=40001"
will actually cause a bind to happen to *:40001 which is what we want and will allow the servers to start
even if there is no netowkr connection. On the other hand, if you use localhost there will be a resolution
failure on startup. This is probably what you should use regardless of the setup of the peer provider factory. -AZ
* port (mandatory) - the port the listener listens on.
* socketTimeoutMillis (optional) - the number of seconds client sockets will wait when sending messages to this
listener until they give up. By default this is 2000ms.
-->
<!-- this will listen for the messages from peers -->
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=127.0.0.1, port=40001" />
</ehcache>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd"
default-autowire-candidates="*Service,*DAO,javax.sql.DataSource">
<context:annotation-config /> <!-- allows us to use spring annotations in beans -->
<!-- NOTE: I am not convinced this is a good idea, it is really slow and I think possibly dangerous -AZ -->
<!--
<context:component-scan base-package="org.dspace" name-generator="org.dspace.servicemanager.spring.FullPathBeanNameGenerator" />
-->
<!-- the bean processor interceptor -->
<bean class="org.dspace.servicemanager.spring.DSpaceBeanPostProcessor" />
</beans>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- Place all DSpace core service bean definitions below here -->
<!-- CACHING service beans -->
<bean id="org.dspace.services.CachingService" class="org.dspace.services.caching.CachingServiceImpl" />
<!-- This is the main cache manager -->
<bean id="org.dspace.caching.ehcache.CacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation">
<bean class="org.dspace.servicemanager.spring.ResourceFinder" factory-method="getResourceFromPaths">
<constructor-arg>
<list>
<value>ehcache-config.xml</value>
<value>caching/ehcache-config.xml</value>
</list>
</constructor-arg>
</bean>
</property>
</bean>
<!-- CACHING end beans -->
<!-- SESSION - session and request services (implemented as a single bean) -->
<bean id="org.dspace.services.SessionService" class="org.dspace.services.sessions.SessionRequestServiceImpl" />
<alias alias="org.dspace.services.RequestService" name="org.dspace.services.SessionService" />
<!-- SESSION end beans -->
<!-- EVENTS -->
<bean id="org.dspace.services.EventService" class="org.dspace.services.events.SystemEventService" />
</beans>

View File

@@ -0,0 +1,108 @@
/**
* $Id: DSpaceKernelImplTest.java 3409 2009-01-30 12:04:43Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/DSpaceKernelImplTest.java $
* DSpaceKernelImplTest.java - DSpace2 - Oct 6, 2008 4:05:54 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import static org.junit.Assert.*;
import java.net.URL;
import java.net.URLClassLoader;
import org.dspace.kernel.DSpaceKernel;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Test the kernel can fire up correctly
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceKernelImplTest {
DSpaceKernelImpl kernelImpl;
@Before
public void init() {
kernelImpl = DSpaceKernelInit.getKernel(null); // checks for the existing kernel but does not init
}
@After
public void destroy() {
if (kernelImpl != null) {
kernelImpl.destroy();
}
kernelImpl = null;
}
/**
* Test method for {@link org.dspace.servicemanager.DSpaceKernelImpl#init()}.
*/
@Test
public void testKernel() {
kernelImpl.start();
assertNotNull(kernelImpl);
DSpaceKernel kernel = kernelImpl.getManagedBean();
assertNotNull(kernel);
assertNotNull(kernelImpl.getConfigurationService());
assertNotNull(kernelImpl.getServiceManager());
assertNotNull(kernel.getConfigurationService());
assertNotNull(kernel.getServiceManager());
assertEquals(kernel.getConfigurationService(), kernelImpl.getConfigurationService());
assertEquals(kernel.getServiceManager(), kernelImpl.getServiceManager());
kernelImpl.stop();
}
@Test
public void testMultipleKernels() {
assertNotNull(kernelImpl);
kernelImpl.start();
DSpaceKernel kernel = kernelImpl.getManagedBean();
assertNotNull(kernel);
assertNotNull(kernelImpl.getConfigurationService());
assertNotNull(kernelImpl.getServiceManager());
assertNotNull(kernel.getConfigurationService());
assertNotNull(kernel.getServiceManager());
assertEquals(kernel.getConfigurationService(), kernelImpl.getConfigurationService());
assertEquals(kernel.getServiceManager(), kernelImpl.getServiceManager());
DSpaceKernelImpl kernelImpl2 = DSpaceKernelInit.getKernel("AZ-kernel"); // checks for the existing kernel but does not init
kernelImpl2.start();
DSpaceKernel kernel2 = kernelImpl2.getManagedBean();
assertNotNull(kernel2);
assertNotNull(kernelImpl2.getConfigurationService());
assertNotNull(kernelImpl2.getServiceManager());
assertNotNull(kernel2.getConfigurationService());
assertNotNull(kernel2.getServiceManager());
assertEquals(kernel2.getConfigurationService(), kernelImpl2.getConfigurationService());
assertEquals(kernel2.getServiceManager(), kernelImpl2.getServiceManager());
assertNotSame(kernel, kernel2);
assertNotSame(kernel.getConfigurationService(), kernel2.getConfigurationService());
assertNotSame(kernel.getServiceManager(), kernel2.getServiceManager());
kernelImpl2.stop();
kernelImpl.stop();
}
@Test
public void testClassLoaders() {
ClassLoader current = Thread.currentThread().getContextClassLoader();
ClassLoader cl1 = new URLClassLoader(new URL[0], current);
cl1.getParent();
// TODO
}
}

View File

@@ -0,0 +1,65 @@
/**
* $Id: DSpaceKernelManagerTest.java 3409 2009-01-30 12:04:43Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/DSpaceKernelManagerTest.java $
* DSpaceKernelManagerTest.java - DSpace2 - Oct 6, 2008 7:23:54 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import static org.junit.Assert.*;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.DSpaceKernelManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Testing the kernel manager
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceKernelManagerTest {
DSpaceKernelManager kernelManager;
DSpaceKernelImpl kernelImpl;
@Before
public void init() {
kernelImpl = DSpaceKernelInit.getKernel(null);
kernelImpl.start(); // init the kernel
kernelManager = new DSpaceKernelManager();
}
@After
public void destroy() {
if (kernelImpl != null) {
// cleanup the kernel
kernelImpl.stop();
kernelImpl.destroy();
}
kernelImpl = null;
}
/**
* Test method for {@link org.dspace.kernel.DSpaceKernelManager#getKernel()}.
*/
@Test
public void testGetKernel() {
DSpaceKernel kernel = kernelManager.getKernel();
assertNotNull(kernel);
DSpaceKernel k2 = kernelManager.getKernel();
assertNotNull(k2);
assertEquals(kernel, k2);
}
}

View File

@@ -0,0 +1,325 @@
/**
* $Id: DSpaceServiceManagerTest.java 3409 2009-01-30 12:04:43Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/DSpaceServiceManagerTest.java $
* DSpaceServiceManagerTest.java - DSpace2 - Oct 6, 2008 4:00:53 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dspace.kernel.mixins.InitializedService;
import org.dspace.kernel.mixins.ShutdownService;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.dspace.servicemanager.example.ConcreteExample;
import org.dspace.servicemanager.fakeservices.FakeService1;
import org.dspace.servicemanager.fakeservices.FakeService2;
import org.dspace.servicemanager.spring.SpringAnnotationBean;
import org.dspace.servicemanager.spring.TestSpringServiceManager;
import org.dspace.services.ConfigurationService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* testing the main dspace service manager
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceServiceManagerTest {
DSpaceServiceManager dsm;
DSpaceConfigurationService configurationService;
@Before
public void init() {
configurationService = new DSpaceConfigurationService();
configurationService.loadConfig("testName@" + SampleAnnotationBean.class.getName(), "beckyz");
configurationService.loadConfig("fakeParam@fakeBean", "beckyz");
dsm = new DSpaceServiceManager(configurationService, TestSpringServiceManager.SPRING_TEST_CONFIG_FILE);
}
@After
public void shutdown() {
if (dsm != null) {
dsm.shutdown();
}
dsm = null;
configurationService = null;
}
/**
* Test method for {@link org.dspace.servicemanager.DSpaceServiceManager#shutdown()}.
*/
@Test
public void testShutdown() {
dsm.startup();
dsm.shutdown();
}
/**
* Test method for {@link org.dspace.servicemanager.DSpaceServiceManager#startup(java.util.List, ConfigurationService)}.
*/
@Test
public void testStartup() {
// testing we can start this up with cleared config
configurationService.clear();
dsm.startup();
}
@Test
public void testStartupWithConfig() {
// testing we can start this up a real config
dsm.startup();
}
/**
* Test method for {@link org.dspace.servicemanager.DSpaceServiceManager#registerService(java.lang.String, java.lang.Object)}.
*/
@Test
public void testRegisterService() {
dsm.startup();
String name = "myNewService";
dsm.registerService(name, "AZ");
String service = dsm.getServiceByName(name, String.class);
assertNotNull(service);
assertEquals("AZ", service);
try {
dsm.registerService("fakey", (Object)null);
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.servicemanager.DSpaceServiceManager#registerServiceClass(java.lang.String, java.lang.Class)}.
*/
@Test
public void testRegisterServiceClass() {
dsm.startup();
int currentSize = dsm.getServicesByType(SampleAnnotationBean.class).size();
SampleAnnotationBean sab = dsm.registerServiceClass("newAnnote", SampleAnnotationBean.class);
assertNotNull(sab);
List<SampleAnnotationBean> l = dsm.getServicesByType(SampleAnnotationBean.class);
assertNotNull(l);
assertEquals(currentSize+1, l.size());
try {
dsm.registerService("fakey", (Class<?>)null);
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.servicemanager.DSpaceServiceManager#unregisterService(java.lang.String)}.
*/
@Test
public void testUnregisterService() {
dsm.startup();
String name = "myNewService";
dsm.registerService(name, "AZ");
String service = dsm.getServiceByName(name, String.class);
assertNotNull(service);
assertEquals("AZ", service);
dsm.unregisterService(name);
}
/**
* Test method for {@link org.dspace.servicemanager.DSpaceServiceManager#getServiceByName(java.lang.String, java.lang.Class)}.
*/
@Test
public void testGetServiceByName() {
configurationService.clear();
dsm.startup();
ConcreteExample concrete = dsm.getServiceByName(ConcreteExample.class.getName(), ConcreteExample.class);
assertNotNull(concrete);
assertEquals("azeckoski", concrete.getName());
SampleAnnotationBean sab = dsm.getServiceByName(SampleAnnotationBean.class.getName(), SampleAnnotationBean.class);
assertNotNull(sab);
assertEquals(null, sab.getSampleValue());
}
@Test
public void testGetServiceByNameConfig() {
dsm.startup();
ConcreteExample concrete = dsm.getServiceByName(ConcreteExample.class.getName(), ConcreteExample.class);
assertNotNull(concrete);
assertEquals("azeckoski", concrete.getName());
SampleAnnotationBean sab = dsm.getServiceByName(SampleAnnotationBean.class.getName(), SampleAnnotationBean.class);
assertNotNull(sab);
assertEquals("beckyz", sab.getSampleValue());
}
/**
* Test method for {@link org.dspace.servicemanager.DSpaceServiceManager#getServicesByType(java.lang.Class)}.
*/
@Test
public void testGetServicesByType() {
dsm.startup();
int currentSize = dsm.getServicesByType(ConcreteExample.class).size();
assertTrue(currentSize > 0);
List<ConcreteExample> l = dsm.getServicesByType(ConcreteExample.class);
assertNotNull(l);
assertEquals("azeckoski", l.get(0).getName());
List<SampleAnnotationBean> l2 = dsm.getServicesByType(SampleAnnotationBean.class);
assertNotNull(l2);
assertTrue(l2.size() >= 1);
List<ServiceConfig> l3 = dsm.getServicesByType(ServiceConfig.class);
assertNotNull(l3);
assertEquals(0, l3.size());
}
/**
* Test method for {@link org.dspace.servicemanager.DSpaceServiceManager#getServicesNames()}.
*/
@Test
public void testGetServicesNames() {
dsm.startup();
List<String> names = dsm.getServicesNames();
assertNotNull(names);
assertTrue(names.size() >= 3);
}
/**
* Test method for {@link org.dspace.servicemanager.DSpaceServiceManager#isServiceExists(java.lang.String)}.
*/
@Test
public void testIsServiceExists() {
dsm.startup();
String name = ConcreteExample.class.getName();
boolean exists = dsm.isServiceExists(name);
assertTrue(exists);
name = SampleAnnotationBean.class.getName();
exists = dsm.isServiceExists(name);
assertTrue(exists);
name = SpringAnnotationBean.class.getName();
exists = dsm.isServiceExists(name);
assertTrue(exists);
exists = dsm.isServiceExists("XXXXXXXXXXXXXXX");
assertFalse(exists);
}
@Test
public void testGetServices() {
dsm.startup();
Map<String, Object> services = dsm.getServices();
assertNotNull(services);
assertTrue(services.size() > 3);
}
@Test
public void testPushConfig() {
dsm.startup();
Map<String, String> properties = new HashMap<String, String>();
properties.put("some.test.thing", "A value");
dsm.pushConfig(properties);
// TODO need to do a better test here
}
@Test
public void testInitAndShutdown() {
dsm.startup();
SampleAnnotationBean sab = dsm.getServiceByName(SampleAnnotationBean.class.getName(), SampleAnnotationBean.class);
assertNotNull(sab);
assertEquals(1, sab.initCounter);
TestService ts = new TestService();
assertEquals(0, ts.value);
dsm.registerService(TestService.class.getName(), ts);
assertEquals(1, ts.value);
dsm.unregisterService(TestService.class.getName());
assertEquals(2, ts.value);
}
@Test
public void testRegisterProviderLifecycle() {
dsm.startup();
// this tests to see if the lifecycle of a provider is working
String serviceName = "azeckoski.FakeService1";
FakeService1 service = new FakeService1();
assertEquals(0, service.getTriggers());
// now we register it and the init should be called
dsm.registerService(serviceName, service);
assertNotNull(service.getConfigurationService());
assertEquals("init", service.getSomething());
assertEquals(1, service.getTriggers());
// now we do a config change
Map<String, String> properties = new HashMap<String, String>();
properties.put("azeckoski.FakeService1.something", "THING");
dsm.pushConfig(properties);
assertEquals("config:THING", service.getSomething());
assertEquals(2, service.getTriggers());
// now we do a service registration
dsm.registerService("fake2", new FakeService2());
assertEquals("registered:fake2", service.getSomething());
assertEquals(3, service.getTriggers());
// now we unregister
dsm.unregisterService("fake2");
assertEquals("unregistered:fake2", service.getSomething());
assertEquals(4, service.getTriggers());
// now we unregister
dsm.unregisterService(serviceName);
assertEquals("shutdown", service.getSomething());
assertEquals(5, service.getTriggers());
}
public static class TestService implements InitializedService, ShutdownService {
public int value = 0;
public void init() {
value++;
}
public void shutdown() {
value++;
}
}
}

View File

@@ -0,0 +1,228 @@
/**
* $Id: DSpaceTest.java 3283 2008-11-13 18:21:00Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/DSpaceTest.java $
* DSpaceTest.java - DSpace2 - Oct 6, 2008 4:10:10 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import static org.junit.Assert.*;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.DSpaceKernelManager;
import org.dspace.utils.DSpace;
import org.junit.Test;
/**
* Make sure the DSpace static cover works
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceTest {
@Test
public void testDSpaceObject() {
try {
DSpace dspace = new DSpace();
dspace.getServiceManager();
fail("should have thrown exception");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
DSpaceKernelImpl kernelImpl = DSpaceKernelInit.getKernel(null);
kernelImpl.start(); // triggers the init
DSpaceKernel kernel = new DSpaceKernelManager().getKernel();
assertNotNull(kernel);
assertEquals(kernel, kernelImpl);
DSpace dspace = new DSpace();
Object o = dspace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
// repeat a few times
o = dspace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
o = dspace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
DSpace dspace2 = new DSpace();
assertNotNull(dspace2.getServiceManager());
assertEquals(dspace.getServiceManager(), dspace2.getServiceManager());
// REPEAT
kernel = new DSpaceKernelManager().getKernel();
o = dspace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
// repeat a few times
o = dspace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
o = dspace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
kernelImpl.destroy(); // cleanup the kernel
try {
new DSpace();
fail("should have thrown exception");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
}
/*********
@Test
public void testStaticCover() {
try {
DSpace.getServiceManager();
fail("should have thrown exception");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
DSpaceKernelImpl kernelImpl = DSpaceKernelInit.getKernel(null);
kernelImpl.start(); // triggers the init
DSpaceKernel kernel = new DSpaceKernelManager().getKernel();
assertNotNull(kernel);
assertEquals(kernel, kernelImpl);
Object o = DSpace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
// repeat a few times
o = DSpace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
o = DSpace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
// REPEAT
kernel = new DSpaceKernelManager().getKernel(); // init the kernel
o = DSpace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
// repeat a few times
o = DSpace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
o = DSpace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
kernelImpl.destroy(); // cleanup the kernel
try {
DSpace.getServiceManager();
fail("should have thrown exception");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void testRestarts() {
try {
DSpace.getServiceManager();
fail("should have thrown exception");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
DSpaceKernelImpl kernelImpl = DSpaceKernelInit.getKernel(null);
DSpaceKernelImpl kernelImpl2 = DSpaceKernelInit.getKernel(null);
assertEquals(kernelImpl, kernelImpl2);
kernelImpl2 = null;
kernelImpl.start(); // triggers the init
DSpaceKernel kernel = new DSpaceKernelManager().getKernel();
assertNotNull(kernel);
assertEquals(kernel, kernelImpl);
Object o = DSpace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
kernelImpl.stop(); // stop the kernel
try {
DSpace.getServiceManager();
fail("should have thrown exception");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
kernelImpl.start(); // triggers the init
kernel = new DSpaceKernelManager().getKernel();
o = DSpace.getServiceManager();
assertNotNull(o);
assertEquals(o, kernel.getServiceManager());
kernelImpl.stop(); // stop the kernel
try {
DSpace.getServiceManager();
fail("should have thrown exception");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
kernelImpl2 = DSpaceKernelInit.getKernel(null);
// check it is the same
assertEquals(kernelImpl, kernelImpl2);
kernelImpl2.start(); // triggers the init
DSpaceKernel kernel2 = new DSpaceKernelManager().getKernel();
assertNotNull(kernel2);
assertEquals(kernel2, kernelImpl2);
assertEquals(kernel, kernel2);
Object o2 = DSpace.getServiceManager();
assertNotNull(o2);
assertEquals(o2, kernel2.getServiceManager());
// now try to startup the kernel again (should not start again)
kernelImpl.start();
assertEquals(kernelImpl2.getServiceManager(), kernelImpl.getServiceManager());
kernelImpl2.destroy(); // cleanup the kernel
kernelImpl.destroy(); // should not fail
try {
DSpace.getServiceManager();
fail("should have thrown exception");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
}
******/
}

View File

@@ -0,0 +1,111 @@
/**
* $Id: MockServiceManagerSystem.java 3232 2008-10-24 10:41:37Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/MockServiceManagerSystem.java $
* MockServiceManagerSystem.java - DSpace2 - Oct 24, 2008 11:15:02 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import java.util.List;
import java.util.Map;
/**
* This Mock allows us to pretend that a SMS is its own parent,
* for testing use only
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class MockServiceManagerSystem implements ServiceManagerSystem {
private final ServiceManagerSystem sms;
public MockServiceManagerSystem(ServiceManagerSystem sms) {
this.sms = sms;
}
/* (non-Javadoc)
* @see org.dspace.servicemanager.ServiceManagerSystem#getServices()
*/
public Map<String, Object> getServices() {
return this.sms.getServices();
}
/* (non-Javadoc)
* @see org.dspace.servicemanager.ServiceManagerSystem#shutdown()
*/
public void shutdown() {
this.sms.shutdown();
}
/* (non-Javadoc)
* @see org.dspace.servicemanager.ServiceManagerSystem#startup()
*/
public void startup() {
this.sms.startup();
}
/* (non-Javadoc)
* @see org.dspace.servicemanager.ServiceManagerSystem#unregisterService(java.lang.String)
*/
public void unregisterService(String name) {
this.sms.unregisterService(name);
}
/* (non-Javadoc)
* @see org.dspace.kernel.ServiceManager#getServiceByName(java.lang.String, java.lang.Class)
*/
public <T> T getServiceByName(String name, Class<T> type) {
return this.sms.getServiceByName(name, type);
}
/* (non-Javadoc)
* @see org.dspace.kernel.ServiceManager#getServicesByType(java.lang.Class)
*/
public <T> List<T> getServicesByType(Class<T> type) {
return this.sms.getServicesByType(type);
}
/* (non-Javadoc)
* @see org.dspace.kernel.ServiceManager#getServicesNames()
*/
public List<String> getServicesNames() {
return this.sms.getServicesNames();
}
/* (non-Javadoc)
* @see org.dspace.kernel.ServiceManager#isServiceExists(java.lang.String)
*/
public boolean isServiceExists(String name) {
return this.sms.isServiceExists(name);
}
/* (non-Javadoc)
* @see org.dspace.kernel.ServiceManager#pushConfig(java.util.Map)
*/
public void pushConfig(Map<String, String> settings) {
this.sms.pushConfig(settings);
}
/* (non-Javadoc)
* @see org.dspace.kernel.ServiceManager#registerService(java.lang.String, java.lang.Object)
*/
public void registerService(String name, Object service) {
this.sms.registerService(name, service);
}
/* (non-Javadoc)
* @see org.dspace.kernel.ServiceManager#registerServiceClass(java.lang.String, java.lang.Class)
*/
public <T> T registerServiceClass(String name, Class<T> type) {
return this.sms.registerServiceClass(name, type);
}
}

View File

@@ -0,0 +1,76 @@
/**
* $Id: SampleAnnotationBean.java 3501 2009-02-26 14:04:46Z grahamtriggs $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/SampleAnnotationBean.java $
* SampleAnnotationBean.java - DSpace2 - Oct 5, 2008 11:25:47 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import org.dspace.kernel.mixins.InitializedService;
import org.dspace.kernel.mixins.ShutdownService;
import org.dspace.servicemanager.example.ConcreteExample;
import org.dspace.servicemanager.example.ServiceExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Service;
/**
* This bean is a simple example of a bean which is annotated as a spring bean and should be found when the AC starts up
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
@Service
public class SampleAnnotationBean implements InitializedService, ShutdownService {
public int initCounter = 0;
public void init() {
initCounter++;
}
public void shutdown() {
initCounter++;
}
private ServiceExample serviceExample;
@Autowired
@Required
public void setServiceExample(ServiceExample serviceExample) {
this.serviceExample = serviceExample;
}
private ConcreteExample concreteExample;
@Autowired
@Required
public void setConcreteExample(ConcreteExample concreteExample) {
this.concreteExample = concreteExample;
}
public String getExampleName() {
return serviceExample.getName();
}
public String getOtherName() {
return serviceExample.getOtherName();
}
public String getConcreteName() {
return concreteExample.getName();
}
private String value = null;
public void setTestName(String value) {
this.value = value;
}
public String getSampleValue() {
return value;
}
}

View File

@@ -0,0 +1,373 @@
/**
* $Id: ServiceMixinManagerTest.java 3241 2008-10-27 15:15:21Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/ServiceMixinManagerTest.java $
* ServiceMixinManagerTest.java - DSpace2 - Oct 27, 2008 11:54:22 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager;
import static org.junit.Assert.*;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Observer;
import org.dspace.kernel.mixins.ConfigChangeListener;
import org.dspace.kernel.mixins.InitializedService;
import org.dspace.kernel.mixins.ServiceChangeListener;
import org.dspace.kernel.mixins.ShutdownService;
import org.dspace.servicemanager.ServiceMixinManager.ServiceHolder;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.dspace.servicemanager.fakeservices.FakeService1;
import org.dspace.servicemanager.fakeservices.FakeService2;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Testing the ability to manage service mixins,
* runs without the kernel to test the functionality of this alone
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class ServiceMixinManagerTest {
protected ServiceMixinManager serviceMixinManager;
@Before
public void setUp() {
serviceMixinManager = new ServiceMixinManager();
// register a couple services as tests
serviceMixinManager.registerService(FakeService2.class.getName(), new FakeService2());
serviceMixinManager.registerService("fake2", new FakeService2());
serviceMixinManager.registerService(FakeService1.class.getName(), new FakeService1(new DSpaceConfigurationService()));
}
@After
public void shutDown() {
serviceMixinManager.clear();
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getBiKey(java.lang.String, java.lang.Class)}.
*/
@Test
public void testGetBiKey() {
String bikey = ServiceMixinManager.getBiKey("org.azeckoski.Test", Serializable.class);
assertNotNull(bikey);
assertEquals("org.azeckoski.Test/java.io.Serializable", bikey);
bikey = ServiceMixinManager.getBiKey("org.azeckoski.Test", null);
assertNotNull(bikey);
assertEquals("org.azeckoski.Test", bikey);
try {
ServiceMixinManager.getBiKey(null, Serializable.class);
fail("Should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getServiceName(java.lang.String)}.
*/
@Test
public void testGetServiceName() {
String bikey = "org.azeckoski.Test/java.io.Serializable";
String serviceName = ServiceMixinManager.getServiceName(bikey);
assertNotNull(serviceName);
assertEquals("org.azeckoski.Test", serviceName);
serviceName = ServiceMixinManager.getServiceName("org.azeckoski.Test");
assertNotNull(serviceName);
assertEquals("org.azeckoski.Test", serviceName);
try {
ServiceMixinManager.getServiceName(null);
fail("Should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getMixinName(java.lang.String)}.
*/
@Test
public void testGetMixinName() {
String bikey = "org.azeckoski.Test/java.io.Serializable";
String mixinName = ServiceMixinManager.getMixinName(bikey);
assertNotNull(mixinName);
assertEquals("java.io.Serializable", mixinName);
mixinName = ServiceMixinManager.getMixinName("org.azeckoski.Test");
assertNull(mixinName);
try {
ServiceMixinManager.getMixinName(null);
fail("Should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getMixin(java.lang.String)}.
*/
@Test
public void testGetMixin() {
String bikey = "org.azeckoski.Test/java.io.Serializable";
Class<?> mixin = ServiceMixinManager.getMixin(bikey);
assertNotNull(mixin);
assertEquals(Serializable.class, mixin);
mixin = ServiceMixinManager.getMixin("org.azeckoski.Test");
assertNull(mixin);
try {
ServiceMixinManager.getMixin(null);
fail("Should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#extractMixins(java.lang.Object)}.
*/
@Test
public void testExtractMixins() {
List<Class<?>> mixins = ServiceMixinManager.extractMixins(new FakeService1());
assertNotNull(mixins);
assertEquals(5, mixins.size());
assertTrue(mixins.contains(ConfigChangeListener.class));
assertTrue(mixins.contains(ServiceChangeListener.class));
assertTrue(mixins.contains(InitializedService.class));
assertTrue(mixins.contains(ShutdownService.class));
assertTrue(mixins.contains(Serializable.class));
mixins = ServiceMixinManager.extractMixins(new FakeService2());
assertNotNull(mixins);
assertEquals(3, mixins.size());
assertTrue(mixins.contains(InitializedService.class));
assertTrue(mixins.contains(Comparable.class));
assertTrue(mixins.contains(Serializable.class));
try {
ServiceMixinManager.extractMixins(null);
fail("Should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getServiceByName(java.lang.String)}.
*/
@Test
public void testGetServiceByName() {
Object service = serviceMixinManager.getServiceByName(FakeService2.class.getName());
assertNotNull(service);
assertTrue(service instanceof FakeService2);
service = serviceMixinManager.getServiceByName("fake2");
assertNotNull(service);
assertTrue(service instanceof FakeService2);
service = serviceMixinManager.getServiceByName(FakeService1.class.getName());
assertNotNull(service);
assertTrue(service instanceof FakeService1);
service = serviceMixinManager.getServiceByName("XXXXXXXXXXXXXX");
assertNull(service);
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getServiceByNameAndMixin(java.lang.String, java.lang.Class)}.
*/
@Test
public void testGetServiceByNameAndMixin() {
ServiceChangeListener serviceChangeListener = serviceMixinManager.getServiceByNameAndMixin(FakeService1.class.getName(), ServiceChangeListener.class);
assertNotNull(serviceChangeListener);
FakeService1 service1 = serviceMixinManager.getServiceByNameAndMixin(FakeService1.class.getName(), null);
assertNotNull(service1);
Observer observer = serviceMixinManager.getServiceByNameAndMixin(FakeService1.class.getName(), Observer.class);
assertNull(observer);
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getRegisteredServiceNames()}.
*/
@Test
public void testGetRegisteredServiceNames() {
List<String> names = serviceMixinManager.getRegisteredServiceNames();
assertNotNull(names);
assertEquals(3, names.size());
assertTrue(names.contains("fake2"));
assertTrue(names.contains(FakeService1.class.getName()));
assertTrue(names.contains(FakeService2.class.getName()));
}
@Test
public void testGetRegisteredServices() {
List<Object> services = serviceMixinManager.getRegisteredServices();
assertNotNull(services);
assertEquals(3, services.size());
}
@Test
public void testSize() {
assertEquals(3, serviceMixinManager.size());
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#registerService(java.lang.String, java.lang.Object)}.
*/
@Test
public void testRegisterService() {
serviceMixinManager.registerService("aaronz", new FakeService2());
assertEquals(4, serviceMixinManager.size());
// should not increase the service count
serviceMixinManager.registerService("aaronz", new FakeService2());
assertEquals(4, serviceMixinManager.size());
try {
serviceMixinManager.registerService(null, new FakeService2());
fail("Should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
try {
serviceMixinManager.registerService("aaronz", null);
fail("Should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#unregisterServiceByName(java.lang.String)}.
*/
@Test
public void testUnregisterServiceByName() {
assertEquals(3, serviceMixinManager.size());
assertNotNull(serviceMixinManager.getServiceByName("fake2"));
serviceMixinManager.unregisterServiceByName("fake2");
assertEquals(2, serviceMixinManager.size());
assertNull(serviceMixinManager.getServiceByName("fake2"));
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#unregisterServiceMixin(java.lang.String, java.lang.Class)}.
*/
@Test
public void testUnregisterServiceMixin() {
assertEquals(3, serviceMixinManager.size());
assertNotNull(serviceMixinManager.getServiceByName("fake2"));
assertNotNull(serviceMixinManager.getServiceByNameAndMixin("fake2", Serializable.class));
serviceMixinManager.unregisterServiceMixin("fake2", Serializable.class);
assertEquals(3, serviceMixinManager.size());
assertNotNull(serviceMixinManager.getServiceByName("fake2"));
assertNull(serviceMixinManager.getServiceByNameAndMixin("fake2", Serializable.class));
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getServiceMixins(java.lang.String)}.
*/
@Test
public void testGetServiceMixins() {
List<Class<? extends Object>> mixins = serviceMixinManager.getServiceMixins("fake2");
assertNotNull(mixins);
assertEquals(4, mixins.size());
assertTrue(mixins.contains(FakeService2.class));
assertTrue(mixins.contains(InitializedService.class));
assertTrue(mixins.contains(Comparable.class));
assertTrue(mixins.contains(Serializable.class));
mixins = serviceMixinManager.getServiceMixins(FakeService1.class.getName());
assertNotNull(mixins);
assertEquals(6, mixins.size());
assertTrue(mixins.contains(FakeService1.class));
assertTrue(mixins.contains(ConfigChangeListener.class));
assertTrue(mixins.contains(ServiceChangeListener.class));
assertTrue(mixins.contains(InitializedService.class));
assertTrue(mixins.contains(ShutdownService.class));
assertTrue(mixins.contains(Serializable.class));
mixins = serviceMixinManager.getServiceMixins("XXXXXXXX");
assertNotNull(mixins);
assertEquals(0, mixins.size());
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getRegisteredServiceMixins()}.
*/
@Test
public void testGetRegisteredServiceMixins() {
Map<String, List<Class<? extends Object>>> serviceMixins = serviceMixinManager.getRegisteredServiceMixins();
assertNotNull(serviceMixins);
assertEquals(3, serviceMixins.size());
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getServicesByMixin(java.lang.Class)}.
*/
@Test
public void testGetServicesByMixin() {
List<Serializable> slist = serviceMixinManager.getServicesByMixin(Serializable.class);
assertNotNull(slist);
assertEquals(3, slist.size());
List<Observer> olist = serviceMixinManager.getServicesByMixin(Observer.class);
assertNotNull(olist);
assertEquals(0, olist.size());
List<FakeService2> fs2l = serviceMixinManager.getServicesByMixin(FakeService2.class);
assertNotNull(fs2l);
assertEquals(2, fs2l.size());
List<ServiceChangeListener> scll = serviceMixinManager.getServicesByMixin(ServiceChangeListener.class);
assertNotNull(scll);
assertEquals(1, scll.size());
}
/**
* Test method for {@link org.dspace.servicemanager.ServiceMixinManager#getServiceNamesByMixin(java.lang.Class)}.
*/
@Test
public void testGetServiceHoldersByMixin() {
List<ServiceHolder<Serializable>> slist = serviceMixinManager.getServiceHoldersByMixin(Serializable.class);
assertNotNull(slist);
assertEquals(3, slist.size());
List<ServiceHolder<Observer>> olist = serviceMixinManager.getServiceHoldersByMixin(Observer.class);
assertNotNull(olist);
assertEquals(0, olist.size());
List<ServiceHolder<FakeService2>> fs2l = serviceMixinManager.getServiceHoldersByMixin(FakeService2.class);
assertNotNull(fs2l);
assertEquals(2, fs2l.size());
List<ServiceHolder<ServiceChangeListener>> scll = serviceMixinManager.getServiceHoldersByMixin(ServiceChangeListener.class);
assertNotNull(scll);
assertEquals(1, scll.size());
assertEquals(FakeService1.class.getName(), scll.get(0).getServiceName());
}
}

View File

@@ -0,0 +1,290 @@
/**
* $Id: DSpaceConfigurationServiceTest.java 3525 2009-03-05 16:52:10Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/config/DSpaceConfigurationServiceTest.java $
* DSpaceConfigurationServiceTest.java - DSpace2 - Oct 8, 2008 3:01:39 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.config;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Testing the config service
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceConfigurationServiceTest {
DSpaceConfigurationService configurationService;
@Before
public void init() {
configurationService = new DSpaceConfigurationService();
List<DSpaceConfig> l = new ArrayList<DSpaceConfig>();
l.add( new DSpaceConfig("service.name", "DSpace") );
l.add( new DSpaceConfig("sample.array", "itemA,itemB,itemC") );
l.add( new DSpaceConfig("sample.number", "123") );
l.add( new DSpaceConfig("sample.boolean", "true") );
l.add( new DSpaceConfig("aaronz", "Aaron Zeckoski") );
l.add( new DSpaceConfig("current.user", "${aaronz}") );
l.add( new DSpaceConfig("test.key1", "This is a value") );
l.add( new DSpaceConfig("test.key2", "This is key1=${test.key1}") );
configurationService.loadConfiguration(l, true);
}
@After
public void tearDown() {
configurationService = null;
}
/**
* Test method for {@link org.dspace.servicemanager.config.DSpaceConfigurationService#replaceVariables(java.util.Map)}.
*/
@Test
public void testReplaceVariables() {
List<DSpaceConfig> l = new ArrayList<DSpaceConfig>();
l.add( new DSpaceConfig("service.name", "DSpace") );
l.add( new DSpaceConfig("aaronz", "Aaron Zeckoski") );
l.add( new DSpaceConfig("current.user", "${aaronz}") );
l.add( new DSpaceConfig("test.key1", "This is a value") );
l.add( new DSpaceConfig("test.key2", "This is key1=${test.key1}") );
l.add( new DSpaceConfig("test.key3", "This is key2=${test.key2}") );
Map<String, DSpaceConfig> configMap = new HashMap<String, DSpaceConfig>();
for (DSpaceConfig config : l) {
configMap.put(config.getKey(), config);
}
configurationService.replaceVariables(configMap);
assertEquals(6, configMap.size());
assertEquals("DSpace", configMap.get("service.name").getValue());
assertEquals("Aaron Zeckoski", configMap.get("aaronz").getValue());
assertEquals("Aaron Zeckoski", configMap.get("current.user").getValue());
assertEquals("This is a value", configMap.get("test.key1").getValue());
assertEquals("This is key1=This is a value", configMap.get("test.key2").getValue());
assertEquals("This is key2=This is key1=This is a value", configMap.get("test.key3").getValue());
}
/**
* Test method for {@link org.dspace.servicemanager.config.DSpaceConfigurationService#getAllProperties()}.
*/
@Test
public void testGetAllProperties() {
Map<String, String> props = configurationService.getAllProperties();
assertNotNull(props);
assertEquals(8, props.size());
assertNotNull(props.get("service.name"));
assertEquals("DSpace", props.get("service.name"));
}
/**
* Test method for {@link org.dspace.servicemanager.config.DSpaceConfigurationService#getProperties()}.
*/
@Test
public void testGetProperties() {
Properties props = configurationService.getProperties();
assertNotNull(props);
assertEquals(8, props.size());
assertNotNull(props.get("service.name"));
assertEquals("DSpace", props.get("service.name"));
}
/**
* Test method for {@link org.dspace.servicemanager.config.DSpaceConfigurationService#getProperty(java.lang.String)}.
*/
@Test
public void testGetProperty() {
String prop = configurationService.getProperty("service.name");
assertNotNull(prop);
assertEquals("DSpace", prop);
prop = configurationService.getProperty("XXXXX");
assertNull(prop);
}
/**
* Test method for {@link org.dspace.servicemanager.config.DSpaceConfigurationService#getPropertyAsType(java.lang.String, java.lang.Class)}.
*/
@Test
public void testGetPropertyAsTypeStringClassOfT() {
String prop = configurationService.getPropertyAsType("service.name", String.class);
assertNotNull(prop);
assertEquals("DSpace", prop);
String[] array = configurationService.getPropertyAsType("sample.array", String[].class);
assertNotNull(array);
assertEquals("itemA", array[0]);
assertEquals("itemB", array[1]);
assertEquals("itemC", array[2]);
Integer number = configurationService.getPropertyAsType("sample.number", Integer.class);
assertNotNull(number);
assertEquals(new Integer(123), number);
Boolean bool = configurationService.getPropertyAsType("sample.boolean", Boolean.class);
assertNotNull(bool);
assertEquals(Boolean.TRUE, bool);
assertEquals(123, (int) configurationService.getPropertyAsType("sample.number", int.class) );
assertEquals(true, (boolean) configurationService.getPropertyAsType("sample.boolean", boolean.class) );
prop = configurationService.getPropertyAsType("XXXXX", String.class);
assertNull(prop);
}
/**
* Test method for {@link org.dspace.servicemanager.config.DSpaceConfigurationService#getPropertyAsType(java.lang.String, java.lang.Object)}.
*/
@Test
public void testGetPropertyAsTypeStringT() {
String prop = configurationService.getPropertyAsType("service.name", "DeeSpace");
assertNotNull(prop);
assertEquals("DSpace", prop);
String[] array = configurationService.getPropertyAsType("sample.array", new String[] {"A","B"});
assertNotNull(array);
assertEquals("itemA", array[0]);
assertEquals("itemB", array[1]);
assertEquals("itemC", array[2]);
Integer number = configurationService.getPropertyAsType("sample.number", new Integer(12345));
assertNotNull(number);
assertEquals(new Integer(123), number);
Boolean bool = configurationService.getPropertyAsType("sample.boolean", Boolean.FALSE);
assertNotNull(bool);
assertEquals(Boolean.TRUE, bool);
boolean b = configurationService.getPropertyAsType("sample.boolean", false);
assertTrue(b);
prop = configurationService.getPropertyAsType("XXXXX", "XXX");
assertEquals("XXX", prop);
}
@Test
public void testGetPropertyAsTypeStringTBoolean() {
String prop = configurationService.getProperty("service.fake.thing");
assertNull(prop);
prop = configurationService.getPropertyAsType("service.fake.thing", "Fakey", false);
assertNotNull(prop);
assertEquals("Fakey", prop);
prop = configurationService.getProperty("service.fake.thing");
assertNull(prop);
prop = configurationService.getPropertyAsType("service.fake.thing", "Fakey", true);
assertNotNull(prop);
assertEquals("Fakey", prop);
prop = configurationService.getProperty("service.fake.thing");
assertNotNull(prop);
assertEquals("Fakey", prop);
}
@Test
public void testSetProperty() {
String prop = configurationService.getProperty("newOne");
assertNull(prop);
boolean changed = configurationService.setProperty("newOne", "1111111");
assertTrue(changed);
prop = configurationService.getProperty("newOne");
assertNotNull(prop);
assertEquals("1111111", prop);
prop = configurationService.getProperty("newBool");
assertNull(prop);
changed = configurationService.setProperty("newBool", true);
assertTrue(changed);
prop = configurationService.getProperty("newBool");
assertNotNull(prop);
assertEquals("true", prop);
changed = configurationService.setProperty("newBool", true);
assertFalse(changed);
changed = configurationService.setProperty("newBool", null);
assertTrue(changed);
prop = configurationService.getProperty("newBool");
assertNull(prop);
}
/**
* Test method for {@link org.dspace.servicemanager.config.DSpaceConfigurationService#getConfiguration()}.
*/
@Test
public void testGetConfiguration() {
assertNotNull( configurationService.getConfiguration() );
assertEquals(8, configurationService.getConfiguration().size() );
}
/**
* Test method for {@link org.dspace.servicemanager.config.DSpaceConfigurationService#loadConfig(java.lang.String, java.lang.String)}.
*/
@Test
public void testLoadConfig() {
assertEquals(8, configurationService.getConfiguration().size());
configurationService.loadConfig("newA", "A");
assertEquals(9, configurationService.getConfiguration().size());
assertEquals("A", configurationService.getProperty("newA"));
configurationService.loadConfig("newB", "service is ${service.name}");
assertEquals(10, configurationService.getConfiguration().size());
assertEquals("service is DSpace", configurationService.getProperty("newB"));
configurationService.loadConfig("newA", "aaronz");
assertEquals(10, configurationService.getConfiguration().size());
assertEquals("aaronz", configurationService.getProperty("newA"));
}
/**
* Test method for {@link org.dspace.servicemanager.config.DSpaceConfigurationService#clear()}.
*/
@Test
public void testClear() {
configurationService.clear();
assertEquals(0, configurationService.getAllProperties().size());
}
/**
* Tests the ability of the system to properly extract system properties into the configuration
*/
@Test
public void testGetPropertiesFromSystem() {
DSpaceConfigurationService dscs = new DSpaceConfigurationService();
int size = dscs.getConfiguration().size();
System.setProperty("dspace.az.system.config", "Hello");
System.setProperty("not.dspace", "Adios");
dscs = new DSpaceConfigurationService();
assertEquals(size + 1, dscs.getConfiguration().size());
assertEquals("Hello", dscs.getProperty("az.system.config"));
}
}

View File

@@ -0,0 +1,126 @@
/**
* $Id: FakeService1.java 3299 2008-11-18 14:22:36Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/fakeservices/FakeService1.java $
* FakeService1.java - DSpace2 - Oct 27, 2008 11:57:36 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.fakeservices;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.dspace.kernel.mixins.ConfigChangeListener;
import org.dspace.kernel.mixins.InitializedService;
import org.dspace.kernel.mixins.ServiceChangeListener;
import org.dspace.kernel.mixins.ShutdownService;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
/**
* This is just testing a fake service and running it through some paces to see if the lifecycles work
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class FakeService1 implements ConfigChangeListener, ServiceChangeListener,
InitializedService, ShutdownService, Serializable {
private static final long serialVersionUID = 1L;
public int triggers = 0;
public int getTriggers() {
return triggers;
}
public String something = "aaronz";
public String getSomething() {
return something;
}
public void setSomething(String something) {
this.something = something;
}
public FakeService1() {
}
public FakeService1(ConfigurationService configurationService) {
// for manual construction
this.configurationService = configurationService;
}
private ConfigurationService configurationService;
@Autowired
@Required
public void setConfigurationService(ConfigurationService configurationService) {
this.configurationService = configurationService;
}
public ConfigurationService getConfigurationService() {
return configurationService;
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ConfigChangeListener#configurationChanged(java.util.List, java.util.Map)
*/
public void configurationChanged(List<String> changedSettingNames,
Map<String, String> changedSettings) {
something = "config:" + changedSettings.get("azeckoski.FakeService1.something");
triggers++;
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ServiceChangeListener#serviceRegistered(java.lang.String, java.lang.Object, java.util.List)
*/
public void serviceRegistered(String serviceName, Object service,
List<Class<?>> implementedTypes) {
something = "registered:"+serviceName;
triggers++;
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ServiceChangeListener#serviceUnregistered(java.lang.String, java.lang.Object)
*/
public void serviceUnregistered(String serviceName, Object service) {
something = "unregistered:"+serviceName;
triggers++;
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.InitializedService#init()
*/
public void init() {
something = "init";
triggers = 1; // RESET to 1
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ShutdownService#shutdown()
*/
public void shutdown() {
something = "shutdown";
triggers++;
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ConfigChangeListener#notifyForConfigNames()
*/
public String[] notifyForConfigNames() {
return null; // ALL
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.ServiceChangeListener#notifyForTypes()
*/
public Class<?>[] notifyForTypes() {
return null; // ALL
}
}

View File

@@ -0,0 +1,49 @@
/**
* $Id: FakeService2.java 3299 2008-11-18 14:22:36Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/fakeservices/FakeService2.java $
* FakeService2.java - DSpace2 - Oct 27, 2008 12:56:26 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.fakeservices;
import java.io.Serializable;
import org.dspace.kernel.mixins.InitializedService;
/**
* Simple fake service 2
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class FakeService2 implements InitializedService, Comparable<FakeService2>, Serializable {
private static final long serialVersionUID = 1L;
public String data = "data";
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.InitializedService#init()
*/
public void init() {
data = "initData";
}
public int compareTo(FakeService2 o) {
return data.compareTo(o.data);
}
}

View File

@@ -0,0 +1,133 @@
/**
* $Id: DSpaceKernelServletContextListenerTest.java 3474 2009-02-11 12:03:47Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/servlet/DSpaceKernelServletContextListenerTest.java $
* DSpaceKernelServletFilterTest.java - DSpace2 - Oct 30, 2008 1:59:18 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.servlet;
import static org.junit.Assert.*;
import java.io.IOException;
import org.dspace.kernel.DSpaceKernelManager;
import org.dspace.utils.servlet.DSpaceWebappServletFilter;
import org.junit.Test;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.testing.HttpTester;
import org.mortbay.jetty.testing.ServletTester;
/**
* This starts up a jetty server and tests the ability for the servlet filter to start a kernel
* and correctly shut it down
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpaceKernelServletContextListenerTest {
@Test
public void testSampleRequest() {
// make sure no kernel yet
try {
new DSpaceKernelManager().getKernel();
fail("Should have thrown exception");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
ServletTester tester = new ServletTester();
tester.setContextPath("/");
tester.getContext().addEventListener(new DSpaceKernelServletContextListener());
tester.addFilter(DSpaceWebappServletFilter.class, "/*", Handler.REQUEST);
tester.addServlet(SampleServlet.class, "/dspace");
try {
tester.start();
} catch (Exception e) {
fail("Could not start the jetty server: " + e.getMessage());
}
// now there should be a kernel
assertNotNull( new DSpaceKernelManager().getKernel() );
// now fire the request
String jettyRequest =
"GET /dspace HTTP/1.1\r\n"+
"Host: tester\r\n"+
"\r\n";
try {
String content = tester.getResponses(jettyRequest);
assertNotNull(content);
assertTrue(content.contains("DSpaceTest"));
assertFalse(content.contains("session=null"));
assertFalse(content.contains("request=null"));
} catch (Exception e) {
fail("Could not fire request: " + e.getMessage());
}
// now there should be a kernel
assertNotNull( new DSpaceKernelManager().getKernel() );
// try a request a different way
HttpTester request = new HttpTester();
HttpTester response = new HttpTester();
request.setMethod("GET");
request.setHeader("Host","tester");
request.setVersion("HTTP/1.0");
request.setURI("/dspace");
try {
response.parse( tester.getResponses(request.generate()) );
} catch (IOException e1) {
fail("Could not parse response: " + e1.getMessage());
} catch (Exception e1) {
fail("Could not parse response: " + e1.getMessage());
}
assertTrue(response.getMethod() == null);
assertEquals(200, response.getStatus());
String content = response.getContent();
assertNotNull(content);
assertTrue(content.contains("DSpaceTest"));
assertFalse(content.contains("session=null"));
assertFalse(content.contains("request=null"));
// now there should be a kernel
assertNotNull( new DSpaceKernelManager().getKernel() );
try {
tester.stop();
} catch (Exception e) {
fail("Could not stop the jetty server: " + e.getMessage());
}
// back to no kernel again
try {
new DSpaceKernelManager().getKernel();
fail("Should have thrown exception");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void testSampleRequestDouble() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
testSampleRequest();
}
}

View File

@@ -0,0 +1,108 @@
/**
* $Id: SampleServlet.java 3523 2009-03-05 14:58:10Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/servlet/SampleServlet.java $
* Example.java - entity-broker - 31 May 2007 7:01:11 PM - azeckoski
**************************************************************************
* Copyright (c) 2007, 2008 Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.osedu.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dspace.servicemanager.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.DSpaceKernelManager;
import org.dspace.kernel.ServiceManager;
import org.dspace.services.RequestService;
import org.dspace.services.SessionService;
/**
* Test servlet for trying out the jetty server
*
* @author Aaron Zeckoski (aaron@caret.cam.ac.uk)
*/
public class SampleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private transient SessionService sessionService;
private transient RequestService requestService;
@Override
public void init() throws ServletException {
super.init();
try {
DSpaceKernel kernel = new DSpaceKernelManager().getKernel();
if (kernel == null) {
throw new IllegalStateException("Could not get the DSpace Kernel");
}
if (! kernel.isRunning()) {
throw new IllegalStateException("DSpace Kernel is not running, cannot startup the DirectServlet");
}
ServiceManager serviceManager = kernel.getServiceManager();
sessionService = serviceManager.getServiceByName(SessionService.class.getName(), SessionService.class);
if (sessionService == null) {
throw new IllegalStateException("Could not get the DSpace SessionService");
}
requestService = serviceManager.getServiceByName(RequestService.class.getName(), RequestService.class);
if (requestService == null) {
throw new IllegalStateException("Could not get the DSpace RequestService");
}
System.out.println("Servlet initialized");
} catch (Exception e) {
throw new IllegalStateException("FAILURE during init of direct servlet: " + e.getMessage(), e);
}
}
/**
* Now this will handle all kinds of requests and not just post and get
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// force all response encoding to UTF-8 / html by default
res.setContentType("text/html");
res.setCharacterEncoding("UTF-8");
// now handle the request
PrintWriter writer = res.getWriter();
writer.print(XML_HEADER);
writer.print(XHTML_HEADER);
writer.print("DSpaceTest:session=" + sessionService.getCurrentSessionId() + ":request=" + requestService.getCurrentRequestId());
writer.print(XHTML_FOOTER);
res.setStatus(HttpServletResponse.SC_OK);
System.out.println("Serviced request: DSpace");
}
protected static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
protected static final String XHTML_HEADER = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" " +
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" +
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
"<head>\n" +
" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" +
" <title>DSpace title</title>\n" +
"</head>\n" +
"<body>\n";
// include versions info in the footer now
protected static final String XHTML_FOOTER = "\n</body>\n</html>\n";
}

View File

@@ -0,0 +1,66 @@
/**
* $Id: SpringAnnotationBean.java 3211 2008-10-16 13:22:12Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/spring/SpringAnnotationBean.java $
* SampleAnnotationBean.java - DSpace2 - Oct 5, 2008 11:25:47 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.spring;
import org.dspace.servicemanager.example.ConcreteExample;
import org.dspace.servicemanager.example.ServiceExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Service;
/**
* This bean is a bean which is annotated as a spring bean and should be found when the AC starts up
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
@Service
public class SpringAnnotationBean {
private ServiceExample serviceExample;
@Autowired
@Required
public void setServiceExample(ServiceExample serviceExample) {
this.serviceExample = serviceExample;
}
private ConcreteExample concreteExample;
@Autowired
@Required
public void setConcreteExample(ConcreteExample concreteExample) {
this.concreteExample = concreteExample;
}
public String getExampleName() {
return serviceExample.getName();
}
public String getOtherName() {
return serviceExample.getOtherName();
}
public String getConcreteName() {
return concreteExample.getName();
}
private String value = null;
public void setTestName(String testName) {
value = testName;
}
public String getSampleValue() {
return value;
}
}

View File

@@ -0,0 +1,224 @@
/**
* $Id: TestSpringServiceManager.java 3498 2009-02-25 19:08:10Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/servicemanager/spring/TestSpringServiceManager.java $
* TestSpringServiceManager.java - DSpace2 - Oct 5, 2008 11:17:11 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.servicemanager.spring;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.List;
import org.dspace.servicemanager.MockServiceManagerSystem;
import org.dspace.servicemanager.SampleAnnotationBean;
import org.dspace.servicemanager.ServiceConfig;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.dspace.servicemanager.example.ConcreteExample;
import org.dspace.services.ConfigurationService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Testing the spring based service manager
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class TestSpringServiceManager {
public static String SPRING_TEST_CONFIG_FILE = "spring/spring-test-services.xml";
SpringServiceManager ssm;
DSpaceConfigurationService configurationService;
@Before
public void init() {
configurationService = new DSpaceConfigurationService();
configurationService.loadConfig("testName@" + SampleAnnotationBean.class.getName(), "beckyz");
configurationService.loadConfig("fakeParam@fakeBean", "beckyz");
ssm = new SpringServiceManager(new MockServiceManagerSystem(ssm), configurationService, true, true, SPRING_TEST_CONFIG_FILE);
}
@After
public void shutdown() {
if (ssm != null) {
ssm.shutdown();
}
ssm = null;
}
/**
* Test method for {@link org.dspace.servicemanager.spring.SpringServiceManager#startup(java.util.List, ConfigurationService)}.
*/
@Test
public void testStartup() {
// testing we can start this up with null config
configurationService.clear();
ssm.startup();
}
@Test
public void testStartupWithConfig() {
// testing we can start this up a real config
ssm.startup();
}
/**
* Test method for {@link org.dspace.servicemanager.spring.SpringServiceManager#shutdown()}.
*/
@Test
public void testShutdown() {
ssm.startup();
ssm.shutdown();
}
/**
* Test method for {@link org.dspace.servicemanager.spring.SpringServiceManager#getServiceByName(java.lang.String, java.lang.Class)}.
*/
@Test
public void testGetServiceByName() {
configurationService.clear(); // no config
ssm.startup();
ConcreteExample concrete = ssm.getServiceByName(ConcreteExample.class.getName(), ConcreteExample.class);
assertNotNull(concrete);
assertEquals("azeckoski", concrete.getName());
SampleAnnotationBean sab = ssm.getServiceByName(SampleAnnotationBean.class.getName(), SampleAnnotationBean.class);
assertNotNull(sab);
assertEquals(null, sab.getSampleValue());
}
@Test
public void testGetServiceByNameConfig() {
ssm.startup();
ConcreteExample concrete = ssm.getServiceByName(ConcreteExample.class.getName(), ConcreteExample.class);
assertNotNull(concrete);
assertEquals("azeckoski", concrete.getName());
SampleAnnotationBean sab = ssm.getServiceByName(SampleAnnotationBean.class.getName(), SampleAnnotationBean.class);
assertNotNull(sab);
assertEquals("beckyz", sab.getSampleValue());
SpringAnnotationBean spr = ssm.getServiceByName(SpringAnnotationBean.class.getName(), SpringAnnotationBean.class);
assertNotNull(spr);
assertEquals("azeckoski", spr.getConcreteName());
assertEquals("aaronz", spr.getExampleName());
assertEquals(null, spr.getSampleValue());
}
/**
* Test method for {@link org.dspace.servicemanager.spring.SpringServiceManager#getServicesByType(java.lang.Class)}.
*/
@Test
public void testGetServicesByType() {
ssm.startup();
List<ConcreteExample> l = ssm.getServicesByType(ConcreteExample.class);
assertNotNull(l);
assertEquals(1, l.size());
assertEquals("azeckoski", l.get(0).getName());
List<SampleAnnotationBean> l2 = ssm.getServicesByType(SampleAnnotationBean.class);
assertNotNull(l2);
assertEquals(1, l2.size());
List<ServiceConfig> l3 = ssm.getServicesByType(ServiceConfig.class);
assertNotNull(l3);
assertEquals(0, l3.size());
}
/**
* Test method for {@link org.dspace.servicemanager.spring.SpringServiceManager#registerServiceClass(java.lang.String, java.lang.Class)}.
*/
@Test
public void testRegisterServiceClass() {
ssm.startup();
SampleAnnotationBean sab = ssm.registerServiceClass("newAnnote", SampleAnnotationBean.class);
assertNotNull(sab);
List<SampleAnnotationBean> l = ssm.getServicesByType(SampleAnnotationBean.class);
assertNotNull(l);
assertEquals(2, l.size());
try {
ssm.registerService("fakey", (Class<?>)null);
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.servicemanager.spring.SpringServiceManager#registerService(java.lang.String, java.lang.Object)}.
*/
@Test
public void testRegisterService() {
ssm.startup();
String name = "myNewService";
ssm.registerService(name, "AZ");
String service = ssm.getServiceByName(name, String.class);
assertNotNull(service);
assertEquals("AZ", service);
try {
ssm.registerService("fakey", (Object)null);
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
@Test
public void testUnregisterService() {
ssm.startup();
String name = "myNewService";
ssm.registerService(name, "AZ");
String service = ssm.getServiceByName(name, String.class);
assertNotNull(service);
assertEquals("AZ", service);
ssm.unregisterService(name);
}
@Test
public void testGetServicesNames() {
ssm.startup();
List<String> names = ssm.getServicesNames();
assertNotNull(names);
assertTrue(names.size() >= 3);
}
@Test
public void testIsServiceExists() {
ssm.startup();
String name = ConcreteExample.class.getName();
boolean exists = ssm.isServiceExists(name);
assertTrue(exists);
exists = ssm.isServiceExists("XXXXXXXXXXXXXXX");
assertFalse(exists);
}
}

View File

@@ -0,0 +1,227 @@
/**
* $Id: CachingServiceTest.java 3540 2009-03-09 12:37:46Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/services/caching/CachingServiceTest.java $
* CachingServiceTest.java - DSpace2 - Oct 24, 2008 11:45:54 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.caching;
import static org.junit.Assert.*;
import java.util.List;
import org.dspace.services.caching.model.EhcacheCache;
import org.dspace.services.caching.model.MapCache;
import org.dspace.services.model.Cache;
import org.dspace.services.model.CacheConfig;
import org.dspace.services.model.CacheConfig.CacheScope;
import org.dspace.test.DSpaceAbstractKernelTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Testing the caching service
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class CachingServiceTest extends DSpaceAbstractKernelTest {
private CachingServiceImpl cachingService;
@Before
public void init() {
cachingService = getService(CachingServiceImpl.class);
assertNotNull(cachingService);
}
@After
public void tearDown() {
cachingService = null;
}
/**
* Test method for {@link org.dspace.services.caching.CachingServiceImpl#reloadConfig()}.
*/
@Test
public void testReloadConfig() {
// just make sure no failure
cachingService.reloadConfig();
}
/**
* Test method for {@link org.dspace.services.caching.CachingServiceImpl#notifyForConfigNames()}.
*/
@Test
public void testNotifyForConfigNames() {
assertNotNull(cachingService.notifyForConfigNames());
}
/**
* Test method for {@link org.dspace.services.caching.CachingServiceImpl#instantiateEhCache(java.lang.String, org.dspace.services.model.CacheConfig)}.
*/
@Test
public void testInstantiateEhCache() {
EhcacheCache cache = cachingService.instantiateEhCache("aaronz-eh", null); // make default ehcache
assertNotNull(cache);
assertEquals("aaronz-eh", cache.getName());
assertNotNull(cache.getCache());
assertEquals(0, cache.size());
assertNotNull(cache.getConfig());
assertEquals(cache.getConfig().getCacheScope(), CacheScope.INSTANCE);
EhcacheCache cache2 = cachingService.instantiateEhCache("aaronz-eh", null);
assertNotNull(cache2);
assertEquals(cache2, cache);
}
/**
* Test method for {@link org.dspace.services.caching.CachingServiceImpl#instantiateMapCache(java.lang.String, org.dspace.services.model.CacheConfig)}.
*/
@Test
public void testInstantiateMapCache() {
MapCache cache = cachingService.instantiateMapCache("aaronz-map", null);
assertNotNull(cache);
assertEquals("aaronz-map", cache.getName());
assertNotNull(cache.getCache());
assertEquals(0, cache.size());
assertNotNull(cache.getConfig());
assertEquals(cache.getConfig().getCacheScope(), CacheScope.REQUEST);
MapCache cache2 = cachingService.instantiateMapCache("aaronz-map", null);
assertNotNull(cache2);
assertEquals(cache2, cache);
}
/**
* Test method for {@link org.dspace.services.caching.CachingServiceImpl#getCache(java.lang.String, org.dspace.services.model.CacheConfig)}.
*/
@Test
public void testGetCache() {
// test getting ehcache from the config
Cache cache = cachingService.getCache("org.dspace.caching.MemOnly", null);
assertNotNull(cache);
assertEquals("org.dspace.caching.MemOnly", cache.getName());
// test getting ehcache from bean
Cache sampleCache = cachingService.getCache("org.sakaiproject.caching.test.SampleCache", null);
assertNotNull(sampleCache);
assertEquals("org.sakaiproject.caching.test.SampleCache", sampleCache.getName());
// test making new caches
Cache c1 = cachingService.getCache("org.dspace.aztest", null);
assertNotNull(c1);
assertEquals("org.dspace.aztest", c1.getName());
assertEquals(CacheScope.INSTANCE, c1.getConfig().getCacheScope());
assertTrue(c1 instanceof EhcacheCache);
Cache rc1 = cachingService.getCache("org.dspace.request.cache1", new CacheConfig(CacheScope.REQUEST));
assertNotNull(rc1);
assertEquals("org.dspace.request.cache1", rc1.getName());
assertEquals(CacheScope.REQUEST, rc1.getConfig().getCacheScope());
assertTrue(rc1 instanceof MapCache);
// try getting the same one twice
Cache c2 = cachingService.getCache("org.dspace.aztest", null);
assertNotNull(c2);
assertEquals(c1, c2);
}
/**
* Test method for {@link org.dspace.services.caching.CachingServiceImpl#getCaches()}.
*/
@Test
public void testGetCaches() {
List<Cache> caches = cachingService.getCaches();
assertNotNull(caches);
int curSize = caches.size();
assertTrue(curSize > 0);
Cache memCache = cachingService.getCache("org.dspace.caching.MemOnly", null);
assertNotNull(memCache);
assertTrue(caches.contains(memCache));
Cache c1 = cachingService.getCache("org.dspace.aztest.new", null);
assertNotNull(c1);
caches = cachingService.getCaches();
assertNotNull(caches);
assertEquals(curSize+1, caches.size());
assertTrue(caches.contains(c1));
}
/**
* Test method for {@link org.dspace.services.caching.CachingServiceImpl#getStatus(java.lang.String)}.
*/
@Test
public void testGetStatus() {
String status = cachingService.getStatus(null);
assertNotNull(status);
// make sure invalid cache is not a failure
status = cachingService.getStatus("XXXXXXXXX");
assertNotNull(status);
}
/**
* Test method for {@link org.dspace.services.caching.CachingServiceImpl#resetCaches()}.
*/
@Test
public void testResetCaches() {
cachingService.resetCaches();
// now add new cache
Cache c1 = cachingService.getCache("org.dspace.aztest.new", null);
assertNotNull(c1);
c1.put("AZ", "aaron.zeckoski");
c1.put("BZ", "becky.zeckoski");
assertEquals("aaron.zeckoski", c1.get("AZ"));
assertEquals(null, c1.get("CZ"));
assertEquals(2, c1.size());
cachingService.resetCaches();
assertEquals(null, c1.get("AZ"));
assertEquals(0, c1.size());
}
/**
* Test method for {@link org.dspace.services.caching.CachingServiceImpl#destroyCache(java.lang.String)}.
*/
@Test
public void testDestroyCache() {
// destroy existing cache
Cache cache = cachingService.getCache("org.dspace.caching.MemOnly", null);
assertNotNull(cache);
cachingService.destroyCache(cache.getName());
Cache c2 = cachingService.getCache("org.dspace.caching.MemOnly", null);
assertNotNull(c2);
assertNotSame(cache, c2);
// ok to destroy non-existent caches
cachingService.destroyCache("XXXXXXXXXXXX");
// destroy new cache
Cache ca = cachingService.getCache("org.dspace.aztest", null);
assertNotNull(ca);
cachingService.destroyCache(ca.getName());
Cache cb = cachingService.getCache("org.dspace.aztest", null);
assertNotNull(cb);
assertNotSame(ca, cb);
}
}

View File

@@ -0,0 +1,212 @@
/**
* $Id: EhcacheCacheTest.java 3540 2009-03-09 12:37:46Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/services/caching/EhcacheCacheTest.java $
* EhcacheCacheTest.java - DSpace2 - Oct 24, 2008 3:47:22 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.caching;
import static org.junit.Assert.*;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import org.dspace.services.caching.model.EhcacheCache;
import org.dspace.services.model.Cache;
import org.dspace.services.model.CacheConfig;
import org.dspace.services.model.CacheConfig.CacheScope;
import org.dspace.test.DSpaceAbstractKernelTest;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* Testing the functionality of the DSpace caches
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class EhcacheCacheTest extends DSpaceAbstractKernelTest {
static String cacheName = "org.dspace.aaronz.test.Cache";
static CacheManager cacheManager;
static Cache cache = null;
@BeforeClass
public static void initClass() {
CachingServiceImpl cachingService = getService(CachingServiceImpl.class);
cacheManager = cachingService.getCacheManager();
cache = cachingService.getCache(cacheName, new CacheConfig(CacheScope.INSTANCE));
}
@Before
public void init() {
cache.clear();
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#getCache()}.
*/
@Test
public void testGetCache() {
assertTrue(cache instanceof EhcacheCache);
assertNotNull( ((EhcacheCache) cache).getCache() );
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#EhcacheCache(net.sf.ehcache.Ehcache, org.dspace.services.model.CacheConfig)}.
*/
@Test
public void testEhcacheCache() {
cacheManager.addCache("org.dspace.ehcache");
Ehcache ehcache = cacheManager.getEhcache("org.dspace.ehcache");
assertNotNull(ehcache);
EhcacheCache cache = new EhcacheCache(ehcache, new CacheConfig(CacheScope.INSTANCE));
assertEquals("org.dspace.ehcache", cache.getName());
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#getConfig()}.
*/
@Test
public void testGetConfig() {
CacheConfig cacheConfig = cache.getConfig();
assertNotNull(cacheConfig);
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#getName()}.
*/
@Test
public void testGetName() {
String name = cache.getName();
assertNotNull(name);
assertEquals(cacheName, name);
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#clear()}.
*/
@Test
public void testClear() {
cache.put("XX", "XXXX");
assertTrue(cache.size() > 0);
cache.clear();
assertEquals(0, cache.size());
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#exists(java.lang.String)}.
*/
@Test
public void testExists() {
assertFalse(cache.exists("XXX"));
cache.put("XXX", 123);
assertTrue(cache.exists("XXX"));
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#get(java.lang.String)}.
*/
@Test
public void testGet() {
cache.put("XXX", 123);
Integer i = (Integer) cache.get("XXX");
assertNotNull(i);
assertEquals(new Integer(123), i);
Object o = cache.get("YYYYYYYY");
assertNull(o);
try {
cache.get(null);
fail("Should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#look(java.lang.String)}.
*/
@Test
public void testLook() {
cache.put("XXX", "AZ");
String thing = (String) cache.look("XXX");
assertNotNull(thing);
assertEquals("AZ", thing);
// TODO better way to test this
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#put(java.lang.String, java.io.Serializable)}.
*/
@Test
public void testPut() {
assertEquals(0, cache.size());
cache.put("XXX", 123);
assertEquals(1, cache.size());
cache.put("YYY", null);
assertEquals(2, cache.size());
cache.put("XXX", "ABC");
assertEquals(2, cache.size());
cache.put("XXX", null);
assertEquals(2, cache.size());
Object o = cache.get("XXX");
assertNull(o);
try {
cache.put(null, "XXX");
fail("Should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#remove(java.lang.String)}.
*/
@Test
public void testRemove() {
cache.put("XXX", 123);
cache.put("YYY", null);
assertEquals(2, cache.size());
cache.remove("XXX");
assertEquals(1, cache.size());
cache.remove("XXX");
assertEquals(1, cache.size());
cache.remove("ZZZ");
assertEquals(1, cache.size());
try {
cache.remove(null);
fail("Should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.services.caching.model.EhcacheCache#size()}.
*/
@Test
public void testSize() {
assertEquals(0, cache.size());
cache.put("A", "AASSDDFF");
assertEquals(1, cache.size());
cache.put("B", "AASSDDFF");
cache.put("C", "AASSDDFF");
assertEquals(3, cache.size());
}
}

View File

@@ -16,9 +16,9 @@ package org.dspace.services.events;
import static org.junit.Assert.*;
import org.dspace.services.EventService;
import org.dspace.services.RequestService;
import org.dspace.services.model.Event;
import org.dspace.utils.DSpace;
import org.dspace.test.DSpaceAbstractKernelTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -28,18 +28,18 @@ import org.junit.Test;
*
* @author Aaron Zeckoski (azeckoski@gmail.com) - azeckoski - 12:24:17 PM Nov 20, 2008
*/
public class EventServiceTest {
public class EventServiceTest extends DSpaceAbstractKernelTest {
private EventService eventService;
//private RequestService requestService;
private SystemEventService eventService;
private RequestService requestService;
private EventListenerNoFilter listenerNoFilter;
private EventListenerNameFilter listenerNameFilter;
private EventListenerBothFilters listenerBothFilters;
@Before
public void init() {
eventService = new DSpace().getEventService();
eventService = getService(SystemEventService.class);
requestService = getService(RequestService.class);
// create the filters
listenerNoFilter = new EventListenerNoFilter();
listenerNameFilter = new EventListenerNameFilter();
@@ -54,7 +54,7 @@ public class EventServiceTest {
public void tearDown() {
// need to do this to ensure the resources are freed up by junit
eventService = null;
//requestService = null;
requestService = null;
listenerNoFilter = null;
listenerNameFilter = null;
listenerBothFilters = null;
@@ -106,6 +106,52 @@ public class EventServiceTest {
assertEquals(event5, listenerBothFilters.getReceivedEvents().get(2));
}
/**
* Test method for {@link org.dspace.services.events.SystemEventService#queueEvent(org.dspace.services.model.Event)}.
*/
@Test
public void testQueueEvent() {
Event event1 = new Event("test.event.read", "test-resource-1", "11111", false);
Event event2 = new Event("test.event.jump", null, "11111", false);
Event event3 = new Event("some.event.write", "test-resource-2", "11111", true);
Event event4 = new Event("some.event.add", "fake-resource-555", "11111", true);
assertEquals(0, listenerNoFilter.getReceivedEvents().size());
// no request, so it fires now
eventService.queueEvent(event1);
// now check that the listeners were properly triggered
assertEquals(1, listenerNoFilter.getReceivedEvents().size());
// now start a request
requestService.startRequest();
eventService.queueEvent(event2);
eventService.queueEvent(event3);
// not yet fired
assertEquals(1, listenerNoFilter.getReceivedEvents().size());
// fail request
requestService.endRequest(new RuntimeException("die request!"));
// still nothing because fail
assertEquals(1, listenerNoFilter.getReceivedEvents().size());
// try a successful one
requestService.startRequest();
eventService.queueEvent(event2);
eventService.queueEvent(event3);
eventService.queueEvent(event4);
requestService.endRequest(null);
assertEquals(4, listenerNoFilter.getReceivedEvents().size());
assertEquals(event1, listenerNoFilter.getReceivedEvents().get(0));
assertEquals(event2, listenerNoFilter.getReceivedEvents().get(1));
assertEquals(event3, listenerNoFilter.getReceivedEvents().get(2));
assertEquals(event4, listenerNoFilter.getReceivedEvents().get(3));
}
/**
* Test method for {@link org.dspace.services.events.SystemEventService#registerEventListener(org.dspace.services.model.EventListener)}.
*/

View File

@@ -0,0 +1,58 @@
/**
* $Id: MockRequestInterceptor.java 3251 2008-10-29 17:15:31Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/services/session/MockRequestInterceptor.java $
* MockRequestInterceptor.java - DSpace2 - Oct 29, 2008 4:55:59 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.session;
import org.dspace.services.model.RequestInterceptor;
import org.dspace.services.model.Session;
/**
* This is a mock request interceptor for testing
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class MockRequestInterceptor implements RequestInterceptor {
public String state = "";
public int hits = 0;
/* (non-Javadoc)
* @see org.dspace.services.model.RequestInterceptor#onEnd(java.lang.String, org.dspace.services.model.Session, boolean, java.lang.Exception)
*/
public void onEnd(String requestId, Session session, boolean succeeded, Exception failure) {
if (succeeded) {
state = "end:success:" + requestId;
} else {
state = "end:fail:" + requestId;
}
hits++;
}
/* (non-Javadoc)
* @see org.dspace.services.model.RequestInterceptor#onStart(java.lang.String, org.dspace.services.model.Session)
*/
public void onStart(String requestId, Session session) {
state = "start:" + requestId;
hits++;
}
/* (non-Javadoc)
* @see org.dspace.kernel.mixins.OrderedService#getOrder()
*/
public int getOrder() {
return 10;
}
}

View File

@@ -0,0 +1,316 @@
/**
* $Id: SessionRequestServiceImplTest.java 3540 2009-03-09 12:37:46Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/services/session/SessionRequestServiceImplTest.java $
* SessionRequestServiceImplTest.java - DSpace2 - Oct 29, 2008 3:58:55 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.services.session;
import static org.junit.Assert.*;
import java.util.List;
import org.dspace.services.CachingService;
import org.dspace.services.model.Cache;
import org.dspace.services.model.CacheConfig;
import org.dspace.services.model.Session;
import org.dspace.services.model.CacheConfig.CacheScope;
import org.dspace.services.sessions.SessionRequestServiceImpl;
import org.dspace.test.DSpaceAbstractKernelTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Testing the request and session services
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class SessionRequestServiceImplTest extends DSpaceAbstractKernelTest {
private SessionRequestServiceImpl sessionRequestService;
private CachingService cachingService;
@Before
public void before() {
sessionRequestService = getService(SessionRequestServiceImpl.class);
cachingService = getService(CachingService.class);
}
@After
public void after() {
sessionRequestService.clear();
cachingService.resetCaches();
sessionRequestService = null;
cachingService = null;
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#startRequest()}.
*/
@Test
public void testStartRequest() {
String requestId = sessionRequestService.startRequest();
assertNotNull(requestId);
String cacheRID = (String) getRequestCache().get(CachingService.REQUEST_ID_KEY);
assertNotNull(cacheRID);
assertEquals(cacheRID, requestId);
sessionRequestService.endRequest(null);
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#endRequest(java.lang.Exception)}.
*/
@Test
public void testEndRequest() {
String requestId = sessionRequestService.startRequest();
assertNotNull(requestId);
sessionRequestService.endRequest(null);
String cacheRID = (String) getRequestCache().get(CachingService.REQUEST_ID_KEY);
assertNull(cacheRID);
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#registerRequestInterceptor(org.dspace.services.model.RequestInterceptor)}.
*/
@Test
public void testRegisterRequestListener() {
MockRequestInterceptor mri = new MockRequestInterceptor();
sessionRequestService.registerRequestInterceptor(mri);
assertEquals("", mri.state);
assertEquals(0, mri.hits);
String requestId = sessionRequestService.startRequest();
assertEquals(1, mri.hits);
assertTrue( mri.state.startsWith("start") );
assertTrue( mri.state.contains(requestId));
sessionRequestService.endRequest(null);
assertEquals(2, mri.hits);
assertTrue( mri.state.startsWith("end") );
assertTrue( mri.state.contains("success"));
assertTrue( mri.state.contains(requestId));
requestId = sessionRequestService.startRequest();
assertEquals(3, mri.hits);
assertTrue( mri.state.startsWith("start") );
assertTrue( mri.state.contains(requestId));
sessionRequestService.endRequest( new RuntimeException("Oh Noes!") );
assertEquals(4, mri.hits);
assertTrue( mri.state.startsWith("end") );
assertTrue( mri.state.contains("fail"));
assertTrue( mri.state.contains(requestId));
try {
sessionRequestService.registerRequestInterceptor(null);
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#makeSession(java.lang.String)}.
*/
@Test
public void testMakeSession() {
Session session = sessionRequestService.makeSession("AZ-session");
assertNotNull(session);
assertEquals("AZ-session", session.getId());
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#getSession(java.lang.String)}.
*/
@Test
public void testGetSession() {
Session s = sessionRequestService.getSession("aaronz");
assertNull(s);
Session newOne = sessionRequestService.makeSession("aaronz");
s = sessionRequestService.getSession("aaronz");
assertNotNull(s);
assertEquals(newOne, s);
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#getAllActiveSessions()}.
*/
@Test
public void testGetAllActiveSessions() {
List<Session> l = sessionRequestService.getAllActiveSessions();
assertNotNull(l);
assertEquals(0, l.size());
Session newOne = sessionRequestService.makeSession("aaronz");
Session newTwo = sessionRequestService.makeSession("beckyz");
l = sessionRequestService.getAllActiveSessions();
assertNotNull(l);
assertEquals(2, l.size());
newOne.invalidate();
l = sessionRequestService.getAllActiveSessions();
assertNotNull(l);
assertEquals(1, l.size());
newTwo.clear();
l = sessionRequestService.getAllActiveSessions();
assertNotNull(l);
assertEquals(1, l.size());
newTwo.invalidate();
l = sessionRequestService.getAllActiveSessions();
assertNotNull(l);
assertEquals(0, l.size());
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#bindSession(java.lang.String, java.lang.String)}.
*/
@Test
public void testBindSession() {
Session session = null;
try {
sessionRequestService.bindSession("AZ1", "/user/aaronz", "aaronz");
fail("should have thrown exception");
} catch (IllegalArgumentException e) {
assertNotNull(e.getMessage());
}
sessionRequestService.makeSession("AZ1");
session = sessionRequestService.bindSession("AZ1", "/user/aaronz", "aaronz");
assertNotNull(session);
assertEquals("AZ1", session.getId());
assertEquals("/user/aaronz", session.getUserId());
session = sessionRequestService.bindSession("AZ1", null, null);
assertNotNull(session);
assertEquals("AZ1", session.getId());
assertEquals(null, session.getUserId());
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#startSession(java.lang.String)}.
*/
@Test
public void testStartSession() {
Session session = sessionRequestService.startSession("aaronz");
assertNotNull(session);
assertEquals("aaronz", session.getId());
session.invalidate();
// try making one with null
Session s2 = sessionRequestService.startSession(null);
assertNotNull(s2);
assertNotNull(s2.getId());
s2.invalidate();
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#getCurrentSession()}.
*/
@Test
public void testGetCurrentSession() {
Session current = sessionRequestService.getCurrentSession();
assertNull(current);
Session session = sessionRequestService.startSession("aaronz");
assertNotNull(session);
assertEquals("aaronz", session.getId());
current = sessionRequestService.getCurrentSession();
assertNotNull(current);
assertEquals("aaronz", current.getId());
assertEquals(current, session);
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#getCurrentSessionId()}.
*/
@Test
public void testGetCurrentSessionId() {
String current = sessionRequestService.getCurrentSessionId();
assertNull(current);
Session session = sessionRequestService.startSession("aaronz");
assertNotNull(session);
assertEquals("aaronz", session.getId());
current = sessionRequestService.getCurrentSessionId();
assertNotNull(current);
assertEquals("aaronz", current);
assertEquals(current, session.getId());
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#getCurrentUserId()}.
*/
@Test
public void testGetCurrentUserId() {
String current = sessionRequestService.getCurrentUserId();
assertNull(current);
Session session = sessionRequestService.startSession("aaronz");
assertNotNull(session);
assertEquals("aaronz", session.getId());
assertEquals(null, session.getUserId());
current = sessionRequestService.getCurrentUserId();
assertNull(current);
sessionRequestService.bindSession(session.getId(), "/user/aaronz", "aaronz");
current = sessionRequestService.getCurrentUserId();
assertNotNull(current);
assertEquals("/user/aaronz", current);
}
/**
* Test method for {@link org.dspace.services.sessions.SessionRequestServiceImpl#getCurrentRequestId()}.
*/
@Test
public void testGetCurrentRequestId() {
String requestId = sessionRequestService.getCurrentRequestId();
assertNull(requestId); // no request yet
String rid = sessionRequestService.startRequest();
requestId = sessionRequestService.getCurrentRequestId();
assertNotNull(requestId);
assertEquals(rid, requestId);
sessionRequestService.endRequest(null);
requestId = sessionRequestService.getCurrentRequestId();
assertNull(requestId); // no request yet
}
/**
* @return the request storage cache
*/
private Cache getRequestCache() {
Cache cache = cachingService.getCache(CachingService.REQUEST_CACHE, new CacheConfig(CacheScope.REQUEST));
return cache;
}
}

View File

@@ -0,0 +1,62 @@
/**
* $Id: DSpaceAbstractKernelTest.java 3563 2009-03-10 17:31:52Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/test/DSpaceAbstractKernelTest.java $
* DSpaceKernelManagerTest.java - DSpace2 - Oct 6, 2008 7:23:54 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.DSpaceKernelManager;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* This is an abstract class which makes it easier to test things that use the DSpace Kernel,
* this will start and stop the kernel at the beginning of the group of tests that are
* in the junit test class which extends this
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public abstract class DSpaceAbstractKernelTest extends DSpaceAbstractTest {
@BeforeClass
public static void initKernel() {
_initializeKernel();
assertNotNull(kernelImpl);
assertTrue(kernelImpl.isRunning());
assertNotNull(kernel);
}
@AfterClass
public static void destroyKernel() {
_destroyKernel();
}
/**
* Test method for {@link org.dspace.kernel.DSpaceKernelManager#getKernel()}.
*/
@Test
public void testKernelIsInitializedAndWorking() {
assertNotNull(kernel);
assertTrue(kernel.isRunning());
DSpaceKernel k2 = new DSpaceKernelManager().getKernel();
assertNotNull(k2);
assertEquals(kernel, k2);
}
}

View File

@@ -0,0 +1,60 @@
/**
* $Id: DSpaceAbstractRequestTest.java 3563 2009-03-10 17:31:52Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/test/DSpaceAbstractRequestTest.java $
* DSpaceKernelManagerTest.java - DSpace2 - Oct 6, 2008 7:23:54 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.test;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
/**
* This is an abstract class which makes it easier to test things that use the DSpace Kernel
* and includes an automatic request wrapper around every test method which will start and
* end a request, the default behavior is to end the request with a failure which causes
* a rollback and reverts the storage to the previous values
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public abstract class DSpaceAbstractRequestTest extends DSpaceAbstractKernelTest {
/**
* @return the current request ID for the current running request
*/
public String getRequestId() {
return requestId;
}
@BeforeClass
public static void initRequestService() {
_initializeRequestService();
}
@Before
public void startRequest() {
_startRequest();
}
@After
public void endRequest() {
_endRequest();
}
@AfterClass
public static void cleanupRequestService() {
_destroyRequestService();
}
}

View File

@@ -0,0 +1,141 @@
/**
* $Id: DSpaceAbstractTest.java 3563 2009-03-10 17:31:52Z mdiggory $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/test/DSpaceAbstractTest.java $
* DSpaceKernelManagerTest.java - DSpace2 - Oct 6, 2008 7:23:54 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.test;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.ServiceManager;
import org.dspace.servicemanager.DSpaceKernelImpl;
import org.dspace.servicemanager.DSpaceKernelInit;
import org.dspace.services.RequestService;
/**
* This is an abstract class which makes it easier to test things that use the DSpace Kernel
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public abstract class DSpaceAbstractTest {
protected static DSpaceKernelImpl kernelImpl;
/**
* The current kernel for testing
*/
public static DSpaceKernel kernel;
/**
* @return the current kernel running for this test
*/
public static DSpaceKernel getKernel() {
return kernel;
}
/**
* @return the current service manager for this kernel
*/
public static ServiceManager getServiceManager() {
return kernel.getServiceManager();
}
/**
* This starts up the kernel,
* run this before running all your tests (before the test suite),
* do not run this after each individual test
*/
public static void _initializeKernel() {
kernelImpl = DSpaceKernelInit.getKernel(null);
kernelImpl.start(); // init the kernel
kernel = kernelImpl.getManagedBean();
}
/**
* This shuts the kernel down,
* run this at the end of all your tests (after the test suite),
* do not run this after each individual test
*/
public static void _destroyKernel() {
if (kernelImpl != null) {
// cleanup the kernel
try {
kernelImpl.stop();
} catch (Exception e) {
// keep going
}
kernelImpl.destroy();
}
// must null things out or JUnit will not clean them up
kernelImpl = null;
kernel = null;
}
/**
* Gets a service for testing, can be cast to the impl if desired,
* only works if this is the only service of the given type
*
* @param <T>
* @param type the type of the service desired
* @return the service of the type requested
*/
public static <T> T getService(Class<T> type) {
T service = kernel.getServiceManager().getServiceByName(null, type);
if (service == null) {
throw new IllegalStateException("Could not find service ("+type+") in service manager for testing");
}
return service;
}
/**
* The request service
*/
public static RequestService requestService;
public static RequestService getRequestService() {
return requestService;
}
/**
* Holds the current request Id
*/
protected String requestId = null;
/**
* Gets the request service,
* run this before all tests (before the test suite)
*/
public static void _initializeRequestService() {
requestService = getService(RequestService.class);
}
/**
* Cleans up the request service,
* run this after all tests are complete (after the test suite)
*/
public static void _destroyRequestService() {
// must null things out or JUnit will not clean them up
requestService = null;
}
/**
* Starts a request,
* this should be run before each individual test
*/
public void _startRequest() {
requestId = requestService.startRequest();
}
/**
* Ends a request,
* this should be run after each individual test
*/
public void _endRequest() {
requestService.endRequest(new RuntimeException("End of test request ("+requestId+"), standard handling, this is not a failure"));
}
}

View File

@@ -0,0 +1,40 @@
/**
* $Id: TestAbstractDSpaceRequestTest.java 3540 2009-03-09 12:37:46Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/test/TestAbstractDSpaceRequestTest.java $
* TestAbstractDSpaceTest.java - DSpace2 - Oct 21, 2008 4:26:40 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.test;
import static org.junit.Assert.*;
import org.dspace.test.DSpaceAbstractRequestTest;
import org.junit.Test;
/**
* A simple class to test that the abstract request test case works
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class TestAbstractDSpaceRequestTest extends DSpaceAbstractRequestTest {
// nothing needed here
@Test
public void testThisWorks() {
assertNotNull(kernel);
assertTrue(kernel.isRunning());
assertNotNull(getRequestService());
assertNotNull(getRequestId());
assertNotNull( getRequestService().getCurrentRequestId() );
assertEquals(getRequestId(), getRequestService().getCurrentRequestId());
}
}

View File

@@ -0,0 +1,36 @@
/**
* $Id: TestAbstractDSpaceTest.java 3540 2009-03-09 12:37:46Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/impl/src/test/java/org/dspace/test/TestAbstractDSpaceTest.java $
* TestAbstractDSpaceTest.java - DSpace2 - Oct 21, 2008 4:26:40 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.test;
import static org.junit.Assert.*;
import org.dspace.test.DSpaceAbstractKernelTest;
import org.junit.Test;
/**
* A simple class to test that the abstract test case works
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class TestAbstractDSpaceTest extends DSpaceAbstractKernelTest {
// nothing needed here
@Test
public void testThisWorks() {
assertNotNull(kernel);
assertTrue(kernel.isRunning());
}
}

View File

@@ -0,0 +1,518 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd">
<!-- Sets the path to the directory where cache .data files are created.
If the path is a Java System Property it is replaced by
its value in the running VM.
The following properties are translated:
user.home - User's home directory
user.dir - User's current working directory
java.io.tmpdir - Default temp file path -->
<diskStore path="java.io.tmpdir"/>
<!--
Cache configuration
===================
The following attributes are required.
name:
Sets the name of the cache. This is used to identify the cache. It must be unique.
maxElementsInMemory:
Sets the maximum number of objects that will be created in memory
maxElementsOnDisk:
Sets the maximum number of objects that will be maintained in the DiskStore
The default value is zero, meaning unlimited.
eternal:
Sets whether elements are eternal. If eternal, timeouts are ignored and the
element is never expired.
overflowToDisk:
Sets whether elements can overflow to disk when the memory store
has reached the maxInMemory limit.
The following attributes and elements are optional.
timeToIdleSeconds:
Sets the time to idle for an element before it expires.
i.e. The maximum amount of time between accesses before an element expires
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can idle for infinity.
The default value is 0.
timeToLiveSeconds:
Sets the time to live for an element before it expires.
i.e. The maximum time between creation time and when an element expires.
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that and Element can live for infinity.
The default value is 0.
diskPersistent:
Whether the disk store persists between restarts of the Virtual Machine.
The default value is false.
diskExpiryThreadIntervalSeconds:
The number of seconds between runs of the disk expiry thread. The default value
is 120 seconds.
diskSpoolBufferSizeMB:
This is the size to allocate the DiskStore for a spool buffer. Writes are made
to this area and then asynchronously written to disk. The default size is 30MB.
Each spool buffer is used only by its cache. If you get OutOfMemory errors consider
lowering this value. To improve DiskStore performance consider increasing it. Trace level
logging in the DiskStore will show if put back ups are occurring.
memoryStoreEvictionPolicy:
Policy would be enforced upon reaching the maxElementsInMemory limit. Default
policy is Least Recently Used (specified as LRU). Other policies available -
First In First Out (specified as FIFO) and Less Frequently Used
(specified as LFU)
*NOTE: LFU seems to have some possible issues -AZ
Cache elements can also contain sub elements which take the same format of a factory class
and properties. Defined sub-elements are:
* cacheEventListenerFactory - Enables registration of listeners for cache events, such as
put, remove, update, and expire.
* bootstrapCacheLoaderFactory - Specifies a BootstrapCacheLoader, which is called by a
cache on initialisation to prepopulate itself.
* cacheExtensionFactory - Specifies a CacheExtension, a generic mechansim to tie a class
which holds a reference to a cache to the cache lifecycle.
RMI Cache Replication
Each cache that will be distributed needs to set a cache event listener which replicates
messages to the other CacheManager peers. For the built-in RMI implementation this is done
by adding a cacheEventListenerFactory element of type RMICacheReplicatorFactory to each
distributed cache's configuration as per the following example:
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true
asynchronousReplicationIntervalMillis=<number of milliseconds"
propertySeparator="," />
The RMICacheReplicatorFactory recognises the following properties:
* replicatePuts=true|false - whether new elements placed in a cache are
replicated to others. Defaults to true.
* replicateUpdates=true|false - whether new elements which override an
element already existing with the same key are replicated. Defaults to true.
* replicateRemovals=true - whether element removals are replicated. Defaults to true.
* replicateAsynchronously=true | false - whether replications are
asynchronous (true) or synchronous (false). Defaults to true.
* replicateUpdatesViaCopy=true | false - whether the new elements are
copied to other caches (true), or whether a remove message is sent. Defaults to true.
* asynchronousReplicationIntervalMillis=<number of milliseconds> - The asynchronous
replicator runs at a set interval of milliseconds. The default is 1000. The minimum
is 10. This property is only applicable if replicateAsynchronously=true
Cluster Bootstrapping
The RMIBootstrapCacheLoader bootstraps caches in clusters where RMICacheReplicators are
used. It is configured as per the following example:
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"
propertySeparator="," />
The RMIBootstrapCacheLoaderFactory recognises the following optional properties:
* bootstrapAsynchronously=true|false - whether the bootstrap happens in the background
after the cache has started. If false, bootstrapping must complete before the cache is
made available. The default value is true.
* maximumChunkSizeBytes=<integer> - Caches can potentially be very large, larger than the
memory limits of the VM. This property allows the bootstraper to fetched elements in
chunks. The default chunk size is 5000000 (5MB).
Cache Exception Handling
By default, most cache operations will propagate a runtime CacheException on failure. An interceptor,
using a dynamic proxy, may be configured so that a CacheExceptionHandler can be configured to
intercept Exceptions. Errors are not intercepted. It is configured as per the following example:
<cacheExceptionHandlerFactory class="net.sf.ehcache.exceptionhandler.CountingExceptionHandlerFactory"
properties="logLevel=FINE"/>
Caches with ExceptionHandling configured are not of type Cache, but are of type Ehcache only, and are not available
using CacheManager.getCache(), but using CacheManager.getEhcache().
CacheLoader
A CacheLoader may be configured against a cache.
<cacheLoaderFactory class="net.sf.ehcache.loader.CountingCacheLoaderFactory"
properties="type=int,startCounter=10"/>
-->
<!--
Mandatory Default Cache configuration. These settings will be applied to caches
created programmtically using CacheManager.add(String cacheName).
The defaultCache has an implicit name "default" which is a reserved cache name.
-->
<defaultCache
maxElementsInMemory="3000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="1200"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
<!--Predefined caches. Add your cache configuration settings here.
If you do not have a configuration for your cache a WARNING will be issued when the
CacheManager starts
The following attributes are required for defaultCache:
name - Sets the name of the cache. This is used to identify the cache. It must be unique.
maxInMemory - Sets the maximum number of objects that will be created in memory
eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element
is never expired.
timeToIdleSeconds - Sets the time to idle for an element before it expires.
i.e. The maximum amount of time between accesses before an element expires
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can idle for infinity
timeToLiveSeconds - Sets the time to live for an element before it expires.
i.e. The maximum time between creation time and when an element expires.
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can live for infinity
overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
has reached the maxInMemory limit.
-->
<!-- CACHES FOR TESTING -->
<cache name="org.dspace.caching.MemOnly"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="1200"
overflowToDisk="false"
diskSpoolBufferSizeMB="0"
maxElementsOnDisk="0"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</cache>
<cache name="org.dspace.caching.DiskOnly"
maxElementsInMemory="1"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="1200"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</cache>
<!--
<cache name="org.dspace.caching.Distributed"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="10"
timeToLiveSeconds="30"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=false,
replicateRemovals=true "/>
</cache>
<cache name="org.dspace.caching.DistributedDisk"
maxElementsInMemory="5"
eternal="false"
timeToIdleSeconds="10"
timeToLiveSeconds="30"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=false,
replicateRemovals=true "/>
</cache>
-->
<!-- Place configuration for your caches following -->
<!-- this cache tracks the timestamps of the most recent updates to particular tables.
It is important that the cache timeout of the underlying cache implementation be set to a
higher value than the timeouts of any of the query caches. In fact, it is recommended that
the the underlying cache not be configured for expiry at all. -->
<!-- <cache name="org.hibernate.cache.UpdateTimestampsCache"-->
<!-- maxElementsInMemory="6000"-->
<!-- eternal="true"-->
<!-- overflowToDisk="false" />-->
<!-- this cache stores the actual objects pulled out of the DB by hibernate -->
<!-- <cache name="org.hibernate.cache.StandardQueryCache"-->
<!-- maxElementsInMemory="12000"-->
<!-- eternal="false"-->
<!-- timeToIdleSeconds="600"-->
<!-- timeToLiveSeconds="1200"-->
<!-- overflowToDisk="false" />-->
<!-- DISTRIBUTED CACHING
Add cacheEventListenerFactory to the cache
==========================================
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=false,
replicateRemovals=true "/>
For Example:
============
<cache name="org.dspace.authz.api.SecurityService.cache"
maxElementsInMemory="20000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="2400"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="100000"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="120">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=false,
replicateRemovals=true "/>
</cache>
CacheManagerPeerProvider
========================
(Enable for distributed operation)
Specifies a CacheManagerPeerProviderFactory which will be used to create a
CacheManagerPeerProvider, which discovers other CacheManagers in the cluster.
The attributes of cacheManagerPeerProviderFactory are:
* class - a fully qualified factory class name
* properties - comma separated properties having meaning only to the factory.
Ehcache comes with a built-in RMI-based distribution system with two means of discovery of
CacheManager peers participating in the cluster:
* automatic, using a multicast group. This one automatically discovers peers and detects
changes such as peers entering and leaving the group
* manual, using manual rmiURL configuration. A hardcoded list of peers is provided at
configuration time.
Configuring Automatic Discovery:
Automatic discovery is configured as per the following example:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=32"/>
Valid properties are:
* peerDiscovery (mandatory) - specify "automatic"
* multicastGroupAddress (mandatory) - specify a valid multicast group address
* multicastGroupPort (mandatory) - specify a dedicated port for the multicast heartbeat
traffic
* timeToLive - specify a value between 0 and 255 which determines how far the packets will propagate.
By convention, the restrictions are:
0 - the same host
1 - the same subnet
32 - the same site
64 - the same region
128 - the same continent
255 - unrestricted
Configuring Manual Discovery:
Manual discovery is configured as per the following example:
<cacheManagerPeerProviderFactory class=
"net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40000/sampleCache1|//server2:40000/sampleCache1
| //server1:40000/sampleCache2|//server2:40000/sampleCache2"
propertySeparator="," />
Valid properties are:
* peerDiscovery (mandatory) - specify "manual"
* rmiUrls (mandatory) - specify a pipe separated list of rmiUrls, in the form
//hostname:port
The hostname is the hostname of the remote CacheManager peer. The port is the listening
port of the RMICacheManagerPeerListener of the remote CacheManager peer.
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic,
multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=1"
propertySeparator=","
/>
-->
<!--
CacheManagerPeerListener
========================
(Enable for distributed operation)
Specifies a CacheManagerPeerListenerFactory which will be used to create a
CacheManagerPeerListener, which
listens for messages from cache replicators participating in the cluster.
The attributes of cacheManagerPeerListenerFactory are:
class - a fully qualified factory class name
properties - comma separated properties having meaning only to the factory.
Ehcache comes with a built-in RMI-based distribution system. The listener component is
RMICacheManagerPeerListener which is configured using
RMICacheManagerPeerListenerFactory. It is configured as per the following example:
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=fully_qualified_hostname_or_ip,
port=40001,
socketTimeoutMillis=120000"
propertySeparator="," />
All properties are optional. They are:
* hostName - the hostName of the host the listener is running on. Specify
where the host is multihomed and you want to control the interface over which cluster
messages are received. Defaults to the host name of the default interface if not
specified.
* port - the port the listener listens on. This defaults to a free port if not specified.
* socketTimeoutMillis - the number of ms client sockets will stay open when sending
messages to the listener. This should be long enough for the slowest message.
If not specified it defaults 120000ms.
* timeToLive - You can control how far the multicast packets propagate by setting the
badly misnamed time to live. Using the multicast IP protocol, the timeToLive value
indicates the scope or range in which a packet may be forwarded. By convention:
0 is restricted to the same host
1 is restricted to the same subnet
32 is restricted to the same site
64 is restricted to the same region
128 is restricted to the same continent
255 is unrestricted
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
-->
<!-- Sample Distributed cache settings -->
<!-- automatic discovery using tcp multicast
For the multicast version, the IP address is no longer that of the server.
Rather, you need to choose the address and port in a designated range that has been reserved for multicasting.
It is as if the server and all potential clients are agreeing that messages will be left in a particular location.
The available addresses for multicasting are in the range 224.0.0.0 through 239.255.255.255.
You can check for the assigned addresses in this range (http://www.iana.org/assignments/multicast-addresses).
Recommended default is to use the IP address 230.0.0.1 and the port 4446.
-->
<!--
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic,
multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446,
timeToLive=1" />
-->
<!-- manual discovery (you must customize this to include every node in the cluster) -->
<!-- <cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server2:40001/sampleCache11|//server2:40001/sampleCache12" />
-->
<!--
A CacheManagerPeerListener listens for messages from peers to the current CacheManager.
You configure the CacheManagerPeerListener by specifiying a CacheManagerPeerListenerFactory which is used to create
the CacheManagerPeerListener using the plugin mechanism.
The attributes of cacheManagerPeerListenerFactory are:
* class - a fully qualified factory class name
* properties - comma separated properties having meaning only to the factory.
Ehcache comes with a built-in RMI-based distribution system. The listener component is RMICacheManagerPeerListener
which is configured using RMICacheManagerPeerListenerFactory. It is configured as per the following example:
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=localhost, port=40001, socketTimeoutMillis=2000" />
Valid properties are:
* hostName (optional) - the hostName of the host the listener is running on. Specify where the host is
multihomed and you want to control the interface over which cluster messages are received.
The hostname is checked for reachability during CacheManager initialisation.
If the hostName is unreachable, the CacheManager will refuse to start and an CacheException will be thrown
indicating connection was refused.
If unspecified, the hostname will use InetAddress.getLocalHost().getHostAddress(), which corresponds to the
default host network interface.
Warning: Explicitly setting this to localhost refers to the local loopback of 127.0.0.1, which is not network
visible and will cause no replications to be received from remote hosts. You should only use this setting when
multiple CacheManagers are on the same machine.
NOTE: this is not obvious, but if you run a netstat -an | grep LISTEN you will see that the configuration shown below:
properties="hostName=127.0.0.1, port=40001"
will actually cause a bind to happen to *:40001 which is what we want and will allow the servers to start
even if there is no netowkr connection. On the other hand, if you use localhost there will be a resolution
failure on startup. This is probably what you should use regardless of the setup of the peer provider factory. -AZ
* port (mandatory) - the port the listener listens on.
* socketTimeoutMillis (optional) - the number of seconds client sockets will wait when sending messages to this
listener until they give up. By default this is 2000ms.
-->
<!-- this will listen for the messages from peers -->
<!--
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=127.0.0.1, port=40001" />
-->
</ehcache>

View File

@@ -0,0 +1,30 @@
# DSpace test properties
# set DSpace into a testing mode
dspace.testing = true
# set the service manager into a testing mode
service.manager.developing = true
# a list of all extra spring configs we want the service manager to load on start
service.manager.spring.configs=spring/spring-test-services.xml,spring/spring-test-beans.xml
# db test settings
# Types of databases: HSQLDB, DERBY, ORACLE, MYSQL, POSTGRES, DB2, MSSQL
jdbc.database.type = HSQLDB
# HSQLDB settings provided for reference
# jdbc.database.type = HSQLDB
# jdbc.driver.class = org.hsqldb.jdbcDriver
# jdbc.connection.url = jdbc:hsqldb:.
# jdbc.username = sa
# jdbc.password =
# H2 settings provided for reference
# jdbc.database.type = HSQLDB
# jdbc.driver.class = org.h2.Driver
# jdbc.connection.url = jdbc:h2:mem:DSpaceH2
# jdbc.username = sa
# jdbc.password =
# DERBY settings provided for reference
# jdbc.database.type = DERBY
# jdbc.driver.class = org.apache.derby.jdbc.EmbeddedDriver
# jdbc.connection.url = jdbc:derby:DSpaceDerby
# jdbc.username = user1
# jdbc.password = user1

View File

@@ -0,0 +1,7 @@
log4j.rootCategory=info
log4j.rootLogger=info, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern= %p %m [%d] (%F:%L) %n

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- Place all test service bean definitions below here -->
<!-- sample cache bean -->
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="org.dspace.caching.ehcache.CacheManager" />
<property name="cacheName" value="org.dspace.caching.ehcache.SampleCache" />
<property name="maxElementsInMemory" value="1000" />
<property name="diskPersistent" value="false" />
<property name="eternal" value="false" />
<property name="timeToLive" value="10" />
<property name="timeToIdle" value="30" />
</bean>
</beans>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- these beans are needed to pass the basic SM tests -->
<bean id="org.dspace.servicemanager.example.ConcreteExample"
class="org.dspace.servicemanager.example.ConcreteExample" />
<bean id="org.dspace.servicemanager.example.ServiceExample"
class="org.dspace.servicemanager.example.ServiceExampleImpl" />
<bean id="org.dspace.servicemanager.SampleAnnotationBean"
class="org.dspace.servicemanager.SampleAnnotationBean" />
<bean id="org.dspace.servicemanager.spring.SpringAnnotationBean"
class="org.dspace.servicemanager.spring.SpringAnnotationBean" />
<!-- NOTE: do not change this unless you know what you are doing -AZ -->
</beans>

529
pom.xml
View File

@@ -1,16 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>dspace-parent</artifactId>
<groupId>org.dspace</groupId>
<version>1.6.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.dspace</groupId>
<artifactId>dspace-services</artifactId>
<name>DSpace Services framework</name>
<version>1.6.0-SNAPSHOT</version>
<description>DSpace Services Framework, legacy Implmentation build on Plugin Manager.</description>
<packaging>pom</packaging>
<name>DSpace Parent Project</name>
<url>http://projects.dspace.org</url>
<organization>
<name>The DSpace Foundation</name>
<url>http://www.dspace.org</url>
</organization>
<version>2.0.0-SNAPSHOT</version><!-- dspace2.version -->
<build>
<plugins>
<!-- java 1.5 or higher -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<!-- unit testing -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<!--
By default, the surefire plugin will automatically
include all test classes with the following wildcard
patterns: "**/Test*.java" - includes all of its
subdirectory and all java filenames that start with
"Test". "**/*Test.java" - includes all of its
subdirectory and all java filenames that end with
"Test". "**/*TestCase.java" - includes all of its
subdirectory and all java filenames that end with
"TestCase".
-->
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<configuration>
<outputEncoding>UTF-8</outputEncoding>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<modules>
<module>api</module>
<module>impl</module>
<module>utils</module>
</modules>
<repositories>
<repository>
@@ -48,11 +128,40 @@
</snapshots>
</repository>
</repositories>
<!--
Distribution management provides a means to control which
versions of dependency jars are used for compilation and
packaging into the distribution. Rather than placing a version
in your dependencies, look here first to see if its already
strongly defined in dspace-pom and dspace-api.
-->
<dependencyManagement>
<dependencies>
<!-- internal -->
<dependency>
<groupId>org.azeckoski</groupId>
<artifactId>reflectutils</artifactId>
<version>0.9.10</version>
<groupId>org.dspace</groupId>
<artifactId>dspace-services-api</artifactId>
<version>2.0.0-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-services-impl</artifactId>
<version>2.0.0-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-services-utils</artifactId>
<version>2.0.0-SNAPSHOT</version>
<type>jar</type>
</dependency>
<!-- external -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>2.5.6</version>
<type>jar</type>
</dependency>
<dependency>
@@ -61,6 +170,147 @@
<version>2.5.6</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>2.5.6</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>2.5.6</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>2.5.6</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.azeckoski</groupId>
<artifactId>reflectutils</artifactId>
<version>0.9.10</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.sakaiproject</groupId>
<artifactId>generic-dao</artifactId>
<version>0.9.16</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.sakaiproject.entitybus</groupId>
<artifactId>entitybus-api</artifactId>
<version>1.0.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.sakaiproject.entitybus</groupId>
<artifactId>entitybus-utils</artifactId>
<version>1.0.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.sakaiproject.entitybus</groupId>
<artifactId>entitybus-impl</artifactId>
<version>1.0.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.sakaiproject.entitybus</groupId>
<artifactId>entitybus-rest</artifactId>
<version>1.0.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.5.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.guiceyfruit</groupId>
<artifactId>guice-core</artifactId>
<version>2.0-beta-1</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.guiceyfruit</groupId>
<artifactId>guice-spring</artifactId>
<version>2.0-beta-1</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.14</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-servlet-tester</artifactId>
<version>6.1.14</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<version>10.4.2.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.1.107</version>
<type>jar</type>
</dependency>
<!-- JCR/jackrabbit -->
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-core</artifactId>
<version>1.4.8</version>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-api</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr-commons</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr-commons</artifactId>
<version>1.4</version>
</dependency>
<!-- logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
@@ -94,12 +344,259 @@
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.5</version>
<scope>test</scope>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>commons-discovery</groupId>
<artifactId>commons-discovery</artifactId>
<version>0.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.3.1</version>
</dependency>
<!-- logging -->
</dependencies>
</dependencyManagement>
<licenses>
<license>
<name>DSpace Sourcecode License</name>
<url>LICENSE.txt</url>
<distribution>repo</distribution>
<comments> A BSD compatable OSS license for the DSpace codebase.</comments>
</license>
</licenses>
<parent>
<artifactId>dspace-parent</artifactId>
<groupId>org.dspace</groupId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<issueManagement>
<system>Sourceforge Issue Tracking</system>
<url>http://sourceforge.net/tracker/?group_id=19984
</url>
</issueManagement>
<mailingLists>
<mailingList>
<name>DSpace Technical Users List</name>
<subscribe> http://lists.sourceforge.net/mailman/listinfo/dspace-tech
</subscribe>
<unsubscribe> http://lists.sourceforge.net/mailman/listinfo/dspace-tech
</unsubscribe>
<post>dspace-tech AT lists.sourceforge.net</post>
<archive> http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-tech
</archive>
</mailingList>
<mailingList>
<name>DSpace Developers List</name>
<subscribe> http://lists.sourceforge.net/mailman/listinfo/dspace-devel
</subscribe>
<unsubscribe> http://lists.sourceforge.net/mailman/listinfo/dspace-devel
</unsubscribe>
<post>dspace-devel AT lists.sourceforge.net</post>
<archive> http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-devel
</archive>
</mailingList>
<mailingList>
<name>DSpace Manakin List</name>
<subscribe> http://lists.sourceforge.net/mailman/listinfo/dspace-manakin
</subscribe>
<unsubscribe> http://lists.sourceforge.net/mailman/listinfo/dspace-manakin
</unsubscribe>
<post>dspace-manakin AT lists.sourceforge.net</post>
<archive>
http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-manakin
</archive>
</mailingList>
<mailingList>
<name>DSpace SCM Commit Change-Log</name>
<subscribe> http://lists.sourceforge.net/mailman/listinfo/dspace-changelog
</subscribe>
<unsubscribe> http://lists.sourceforge.net/mailman/listinfo/dspace-changelog
</unsubscribe>
<post>noreply AT lists.sourceforge.net</post>
<archive>
http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-changelog
</archive>
</mailingList>
</mailingLists>
<developers>
<developer>
<id>azeckoski</id>
<name>Aaron Zeckoski</name>
<email>azeckoski@gmail.com</email>
<url>http://wiki.sakaiproject.org/confluence/display/~aaronz
</url>
<organization>CARET, University of Cambridge</organization>
<organizationUrl>http://caret.cam.ac.uk/
</organizationUrl>
<roles>
<role>architect</role>
<role>committer</role>
</roles>
<timezone>0</timezone>
</developer>
<developer>
<id>mdiggory</id>
<name>Mark Diggory</name>
<email>mdiggory@atmire.com</email>
<roles>
<role>architect</role>
<role>committer</role>
</roles>
<organization>@mire</organization>
<organizationUrl>http://www.atmire.com</organizationUrl>
<timezone>-8</timezone>
</developer>
</developers>
<contributors>
<contributor>
<name>Add Your Name Here and submit a patch!</name>
<email>contributor at myu.edu</email>
<url>http://www.myu.edu/me</url>
<organization>My University</organization>
<organizationUrl>http://www.myu.edu</organizationUrl>
<roles>
<role>developer</role>
</roles>
<timezone>0</timezone>
</contributor>
</contributors>
<!--
The Subversion repository location is used by Continuum to
update against when changes have occured, this spawns a new
build cycle and releases snapshots into the snapshot repository
below.
-->
<scm>
<connection>scm:svn:http://scm.dspace.org/svn/repo/dspace2/core/trunk</connection>
<developerConnection>scm:svn:https://scm.dspace.org/svn/repo/dspace2/core/trunk</developerConnection>
<url>http://scm.dspace.org/svn/repo/dspace2/core/trunk</url>
</scm>
<!--
Distribution Management is currently used by the Continuum
server to update snapshots it generates. This will also be used
on release to deploy release versions to the repository by the
release manager.
-->
<distributionManagement>
<repository>
<id>maven.dspace.org/release</id>
<name>DSpace Maven Repository</name>
<url>scp://maven.dspace.org/var/maven/release
</url>
</repository>
<snapshotRepository>
<id>maven.dspace.org/snapshot</id>
<name>DSpace Maven Repository</name>
<url>scp://maven.dspace.org/var/maven/snapshot
</url>
<uniqueVersion>false</uniqueVersion>
</snapshotRepository>
<site>
<id>website</id>
<url> scp://projects.dspace.org/var/www/projects.dspace.org/htdocs</url>
</site>
</distributionManagement>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<aggregate>true</aggregate>
<links>
<link>http://java.sun.com/j2se/1.5.0/docs/api</link>
<link>http://java.sun.com/products/servlet/2.4/javadoc/</link>
<link>http://junit.sourceforge.net/javadoc/</link>
</links>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jxr-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jdepend-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>taglist-maven-plugin</artifactId>
<configuration>
<tags>
<tag>TODO</tag>
<tag>FIXME</tag>
<tag>@deprecated</tag>
</tags>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
</plugin>
</plugins>
</reporting>
</project>

View File

@@ -1,92 +0,0 @@
package org.dspace.services;
import java.util.List;
import java.util.Map;
import org.dspace.services.model.ObjectCount;
/**
* @author mdiggory
*
*/
public interface ReportingService {
/**
* @param query
* @param max
* @throws SolrServerException
*/
public void query(String query, int max);
/**
* Query used to get values grouped by the date
*
* @param query
* the query to be used
* @param filterQuery
* @param max
* the max number of values given back (in case of 10 the top 10
* will be given)
* @param dateType
* the type to be used (example: DAY, MONTH, YEAR)
* @param dateStart
* the start date Format:(-3, -2, ..) the date is calculated
* relatively on today
* @param dateEnd
* the end date stop Format (-2, +1, ..) the date is calculated
* relatively on today
* @param showTotal
* a boolean determening whether the total amount should be given
* back as the last element of the array
* @return and array containing our results @ * ...
*/
public ObjectCount[] queryFacetDate(String query, String filterQuery,
int max, String dateType, String dateStart, String dateEnd,
boolean showTotal);
/**
* Query used to get values grouped by the given facetfield
*
* @param query
* the query to be used
* @param filterQuery
* @param facetField
* the facet field on which to group our values
* @param max
* the max number of values given back (in case of 10 the top 10
* will be given)
* @param showTotal
* a boolean determening whether the total amount should be given
* back as the last element of the array
* @param facetQueries
* @return an array containing our results @ * ...
*/
public ObjectCount[] queryFacetField(String query, String filterQuery,
String facetField, int max, boolean showTotal,
List<String> facetQueries);
/**
* @param query
* @param filterQuery
* @param facetQueries
* @return @
*/
public Map<String, Integer> queryFacetQuery(String query,
String filterQuery, List<String> facetQueries);
/**
* @param query
* @param oldFieldVals
* @param field
* @return
*/
public Map<String, List<String>> queryField(String query,
List oldFieldVals, String field);
/**
* @param query
* @param filterQuery
* @return @
*/
public ObjectCount queryTotal(String query, String filterQuery);
}

View File

@@ -1,32 +0,0 @@
package org.dspace.services.model;
/**
* Created by IntelliJ IDEA.
* User: kevinvandevelde
* Date: 24-dec-2008
* Time: 10:04:08
* To change this template use File | Settings | File Templates.
*/
public class ObjectCount {
private long count;
private String value;
public ObjectCount(){
}
public long getCount() {
return count;
}
public void setCount(long count) {
this.count = count;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -1,77 +0,0 @@
/*
* $URL: $
*
* $Revision: $
*
* $Date: $
*
* Copyright (c) 2009, The DSpace Foundation. 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 DSpace Foundation 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
* HOLDERS 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.
*/
package org.dspace.utils;
import org.dspace.servicemanager.config.DSpaceConfigurationService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.EventService;
import org.dspace.services.events.SystemEventService;
/**
* This is the DSpace helper services access object, it allows access to all
* core DSpace services for those who cannot or will not use the injection
* service to get services <br/>
* Note that this may not include every core service but should include all the
* services that are useful to UI developers at least <br/>
* This should be initialized using the constructor and then can be used as long
* as the kernel is not shutdown, making multiple copies of this is cheap and
* can be done without worry about the cost
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
* @author Mark Diggory (mdiggory @ atmire.com)
*/
public class DSpace
{
private static EventService eventService = new SystemEventService();
private static ConfigurationService configService = new DSpaceConfigurationService();
public DSpace()
{
}
public ConfigurationService getConfigurationService() {
return configService;
}
public EventService getEventService() {
return eventService;
}
}

69
utils/pom.xml Normal file
View File

@@ -0,0 +1,69 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dspace</groupId>
<artifactId>dspace-services-utils</artifactId>
<name>DSpace Utilities</name>
<description>The core utilities for DSpace</description>
<url>http://projects.dspace.org</url>
<inceptionYear>2008</inceptionYear>
<parent>
<artifactId>dspace-services</artifactId>
<groupId>org.dspace</groupId>
<version>2.0.0-SNAPSHOT</version><!--dspace2.version-->
</parent>
<organization>
<name>The DSpace Foundation</name>
<url>http://www.dspace.org</url>
</organization>
<packaging>jar</packaging>
<!--
The Subversion repository location is used by Continuum to
update against when changes have occured, this spawns a new
build cycle and releases snapshots into the snapshot repository
below.
-->
<scm>
<connection>scm:svn:http://scm.dspace.org/svn/repo/modules/dspace-services/trunk/utils</connection>
<developerConnection>scm:svn:https://scm.dspace.org/svn/repo/modules/dspace-services/trunk/utils</developerConnection>
<url>http://scm.dspace.org/svn/repo/modules/dspace-services/trunk/utils</url>
</scm>
<repositories>
<repository>
<id>dspace-snapshot</id>
<name>DSpace Snapshot Repository</name>
<url>http://maven.dspace.org/snapshot</url>
<releases>
<enabled>false</enabled>
<checksumPolicy>fail</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-services-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,112 @@
/*
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/utils/src/main/java/org/dspace/utils/DSpace.java $
*
* $Revision: 3607 $
*
* $Date: 2009-03-17 19:33:30 -0700 (Tue, 17 Mar 2009) $
*
* Copyright (c) 2008, The DSpace Foundation. 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 DSpace Foundation 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
* HOLDERS 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.
*/
package org.dspace.utils;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.DSpaceKernelManager;
import org.dspace.kernel.ServiceManager;
import org.dspace.services.ConfigurationService;
import org.dspace.services.EventService;
import org.dspace.services.RequestService;
import org.dspace.services.SessionService;
/**
* This is the DSpace helper services access object,
* it allows access to all core DSpace services for those who cannot or will not use the injection service to get services <br/>
* Note that this may not include every core service but should include all the services that are useful to UI developers at least <br/>
* This should be initialized using the constructor and then can be used as long as the kernel is not shutdown,
* making multiple copies of this is cheap and can be done without worry about the cost
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class DSpace {
private DSpaceKernel kernel;
public DSpaceKernel getKernel() {
return kernel;
}
/**
* Construct a DSpace helper object which uses the default kernel
* @throws IllegalStateException if the kernel is not already running
*/
public DSpace() {
this(null);
}
/**
* Construct a DSpace helper object which uses the a specific named instance of the kernel
* @param kernelName the name of the kernel to use (null to use the default kernel)
* @throws IllegalStateException if the kernel is not already running or no kernel exists with this name
*/
public DSpace(String kernelName) {
DSpaceKernel kernel = new DSpaceKernelManager().getKernel(kernelName);
this.kernel = kernel;
}
public ServiceManager getServiceManager() {
if (kernel == null) {
throw new IllegalStateException("DSpace kernel cannot be null");
}
return kernel.getServiceManager();
}
// place methods to retrieve key services below here -AZ
public ConfigurationService getConfigurationService() {
return getServiceManager().getServiceByName(ConfigurationService.class.getName(), ConfigurationService.class);
}
public EventService getEventService() {
return getServiceManager().getServiceByName(EventService.class.getName(), EventService.class);
}
public SessionService getSessionService() {
return getServiceManager().getServiceByName(SessionService.class.getName(), SessionService.class);
}
public RequestService getRequestService() {
return getServiceManager().getServiceByName(RequestService.class.getName(), RequestService.class);
}
public <T> T getSingletonService(Class<T> type) {
return getServiceManager().getServiceByName(type.getName(), type);
}
}

View File

@@ -0,0 +1,65 @@
/**
* $Id: StreamUtils.java 3434 2009-02-04 18:00:29Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/utils/src/main/java/org/dspace/utils/StreamUtils.java $
* StreamUtils.java - DS2 - Feb 4, 2009 3:19:01 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Simple set of utils which handle various stream operations
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class StreamUtils {
/**
* A simple utility to convert inputstreams into strings
* @param is the input stream
* @return the string version of the IS
*/
public static String convertStreamToString(InputStream is) {
if (is == null) {
throw new IllegalArgumentException("Invalid input stream, cannot be null");
}
/*
* To convert the InputStream to String we use the BufferedReader.readLine()
* method. We iterate until the BufferedReader return null which means
* there's no more data to read. Each line will appended to a StringBuilder
* and returned as String.
*/
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,32 @@
/**
* $Id: NotProvider.java 3533 2009-03-06 12:06:27Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/utils/src/main/java/org/dspace/utils/servicemanager/NotProvider.java $
* NotProvider.java - DS2 - Mar 6, 2009 11:40:10 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.utils.servicemanager;
/**
* This is a special marker interface which is used to indicate that this
* service is not a provider and thus should not be included in the provider stacks
* which are being setup and stored, any service which implements this interface
* will not be able to be added to the provider stack, in some cases this results in
* an exception but it mostly just results in the object being ignored and not placed
* into the stack
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface NotProvider {
// This area intentionally left blank
}

View File

@@ -0,0 +1,64 @@
/**
* $Id: OrderedServiceComparator.java 3678 2009-04-06 12:45:44Z grahamtriggs $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/utils/src/main/java/org/dspace/utils/servicemanager/OrderedServiceComparator.java $
* OrderedBeanComparator.java - DSpace2 - Oct 24, 2008 5:01:44 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.utils.servicemanager;
import java.util.Comparator;
import java.io.Serializable;
import org.dspace.kernel.mixins.OrderedService;
/**
* A comparator for provider beans, filters, and plugins which will
* take ordering into account if {@link OrderedService} is implemented,
* small numbers are ordered first in priority (i.e. are before large ones),
* NOTE that 0 means "not a priority" so it gets placed at the end
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class OrderedServiceComparator implements Comparator<Object>, Serializable {
public final static long serialVersionUID = 1l;
/*
* (non-Javadoc)
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare(Object arg0, Object arg1) {
/* a negative integer, zero, or a positive integer as the first argument
* is less than, equal to, or greater than the second.
*/
int comparison = 0;
if (arg0 instanceof OrderedService &&
arg1 instanceof OrderedService) {
int p0 = ((OrderedService)arg0).getOrder();
int p1 = ((OrderedService)arg1).getOrder();
if (p0 <= 0 && p1 <= 0) {
comparison = 0; // both zero or less so equal
} else if (p0 <= 0) {
comparison = 2; // zero or less should always be after
} else if (p1 <= 0) {
comparison = -2; // zero or less should always be after
} else {
comparison = p0 - p1;
}
} else if (arg0 instanceof OrderedService) {
comparison = -1; // ordered is always before unordered
} else if (arg1 instanceof OrderedService) {
comparison = 1; // ordered is always before unordered
} else {
comparison = 0; // unordered is equivalent
}
return comparison;
}
}

View File

@@ -0,0 +1,129 @@
/**
* $Id: ProviderHolder.java 3477 2009-02-16 15:29:24Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/utils/src/main/java/org/dspace/utils/servicemanager/ProviderHolder.java $
* ProviderHolder.java - DSpace2 - Oct 29, 2008 12:46:32 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.utils.servicemanager;
import java.lang.ref.WeakReference;
/**
* A holder which is designed to make it easy to hold onto a reference to a class which is outside
* of our ClassLoader and not cause it to not be able to reload happily, the reference to the
* object that is held onto here needs to not be the only one in the system or this object
* will be garbage collected before it probably should be, that is generally outside the purvue
* of the service manager system though
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class ProviderHolder<T> {
private WeakReference<T> providerReference = null;
/**
* Default constructor
*/
public ProviderHolder() {}
/**
* Create the holder with a provider already in it
* @param provider the provider to place in the holder to start
*/
public ProviderHolder(T provider) {
setProvider(provider);
}
/**
* Gets the provider out of this holder if it still exists,
* use the {@link #getProviderOrFail()} method if you want a method that never returns null
*
* @return the provider if it is still available OR null if none is set or no longer available
*/
public T getProvider() {
T t = null;
if (this.providerReference != null) {
t = this.providerReference.get();
}
return t;
}
/**
* Gets the provider out of this holder if it still exists,
* will not return null (unlike the {@link #getProvider()} method)
*
* @return the provider if it is available
* @throws ProviderNotFoundException if there is none available
*/
public T getProviderOrFail() {
T t = getProvider();
if (t == null) {
throw new ProviderNotFoundException("Could not get provider from this holder, none available");
}
return t;
}
/**
* Stores a provider in this holder in a ClassLoader safe way
*
* @param provider the provider to store, if this is null then the current provider is cleared
*/
public void setProvider(T provider) {
if (provider == null) {
if (this.providerReference != null) {
this.providerReference.clear();
}
this.providerReference = null;
} else {
this.providerReference = new WeakReference<T>(provider);
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
T provider = getProvider();
result = prime * result + ((provider == null) ? 0 : provider.hashCode());
return result;
}
@Override
@SuppressWarnings("unchecked")
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ProviderHolder<T> other = (ProviderHolder<T>) obj;
T provider = getProvider();
T otherProvider = other.getProvider();
if (provider == null || otherProvider == null) {
return false;
} else if (provider.equals(otherProvider)) {
return true;
}
return false;
}
@Override
public String toString() {
T provider = getProvider();
return "ph:" + (provider == null ? null : provider.getClass() + ":" + provider) + ": " + super.toString();
}
}

View File

@@ -0,0 +1,33 @@
/**
* $Id: ProviderNotFoundException.java 3477 2009-02-16 15:29:24Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/utils/src/main/java/org/dspace/utils/servicemanager/ProviderNotFoundException.java $
* ProviderNotFoundException.java - DS2 - Feb 16, 2009 2:34:56 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.utils.servicemanager;
/**
* This exception indicates that the provider was not found (the reference was collected)
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class ProviderNotFoundException extends RuntimeException {
public ProviderNotFoundException(String message, Throwable cause) {
super(message, cause);
}
public ProviderNotFoundException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,306 @@
/**
* $Id: ProviderStack.java 3858 2009-06-04 11:51:04Z azeckoski $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/utils/src/main/java/org/dspace/utils/servicemanager/ProviderStack.java $
* ProviderStack.java - DS2 - Feb 12, 2009 10:10:45 AM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.utils.servicemanager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Vector;
import org.dspace.kernel.ServiceManager;
import org.dspace.kernel.mixins.OrderedService;
/**
* This class stores a list of providers in a specific order
* (determined by insertion order and the {@link OrderedService} settings) <br/>
* Should be thread safe
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class ProviderStack<T> {
protected final Vector<ProviderHolder<T>> providers;
/**
* Default empty constructor <br/>
* This is mostly only useful if you are planning to add new providers later,
* you should probably use the other contructors
*/
public ProviderStack() {
providers = new Vector<ProviderHolder<T>>();
}
/**
* Construct a provider holder with all currently known providers of the given type
* @param serviceManager the system service manager
* @param providerType the interface type of the providers we care about
*/
public ProviderStack(ServiceManager serviceManager, Class<T> providerType) {
providers = new Vector<ProviderHolder<T>>();
List<T> foundProviders = serviceManager.getServicesByType(providerType);
// filter out the NotProviders first
for (Iterator<T> iterator = foundProviders.iterator(); iterator.hasNext();) {
T t = iterator.next();
if (t instanceof NotProvider) {
iterator.remove();
}
}
Collections.sort(foundProviders, new OrderedServiceComparator());
for (T t : foundProviders) {
providers.add( new ProviderHolder<T>(t) );
}
}
/**
* Construct a provider holder with a given set of providers,
* this will maintain the current order as long as it does not violate the rules for {@link OrderedService}s
* @param currentProviders the current set of providers to register in this stack
*/
public ProviderStack(T[] currentProviders) {
providers = new Vector<ProviderHolder<T>>();
ArrayList<T> tList = new ArrayList<T>();
// first add in the ordered ones
for (int i = 0; i < currentProviders.length; i++) {
T t = currentProviders[i];
if (t instanceof NotProvider) {
continue; // skip all the NotProviders
}
if (t instanceof OrderedService) {
tList.add( t );
}
}
// sort the ordered ones
Collections.sort(tList, new OrderedServiceComparator());
// now add in the rest in the order given
for (int i = 0; i < currentProviders.length; i++) {
T t = currentProviders[i];
if (! (t instanceof OrderedService)) {
if (t instanceof NotProvider) {
continue; // skip all the NotProviders
}
tList.add( t );
}
}
// now put these into holders
for (T t : tList) {
providers.add( new ProviderHolder<T>(t) );
}
tList.clear();
}
/**
* Add a provider to the stack of providers,
* this will be placed at the bottom if the order is less than or equal to 0 or this provider is not ordered
*
* @param provider the provider to add to the stack
* @return the position in the stack that this provider was added
*/
public int addProvider(T provider) {
if (provider == null) {
throw new IllegalArgumentException("provider to add cannot be null");
}
int position = 0;
refresh();
int providerOrder = 0;
if (provider instanceof NotProvider) {
throw new IllegalArgumentException("Cannot place anything that implements NotProvider into the provider stack, failure for: " + provider);
}
if (provider instanceof OrderedService) {
providerOrder = ((OrderedService)provider).getOrder();
}
// place at the bottom of the stack
providers.add( new ProviderHolder<T>(provider) );
if (providerOrder > 0) {
// re-sort the providers
Collections.sort(this.providers, new ProviderStackComparator());
}
return position;
}
/**
* Remove a provider based on the position in the stack (starting at 0 and ending at size-1)
* @param position the position to remove the provider from
* @return true if the provider position was found and removed OR false if not found
*/
public boolean removeProvider(final int position) {
boolean removed = false;
try {
this.providers.remove(position);
removed = true;
} catch (ArrayIndexOutOfBoundsException e) {
removed = false;
}
refresh();
return removed;
}
/**
* Remove a provider by the object equality
* @param provider the provider to remove from the stack
* @return true if the provider was found and removed OR false if not found
*/
public boolean removeProvider(T provider) {
if (provider == null) {
throw new IllegalArgumentException("provider to remove cannot be null");
}
boolean removed = false;
refresh();
for (Iterator<ProviderHolder<T>> iterator = providers.iterator(); iterator.hasNext();) {
ProviderHolder<T> holder = iterator.next();
T p = holder.getProvider();
if (p == null) {
iterator.remove();
} else {
if (p.equals(provider)) {
iterator.remove();
removed = true;
}
}
}
return removed;
}
/**
* Get the list of all providers currently in the stack <br/>
* WARNING: this should not be held onto and should be only used for iteration and then discarded
* @return a read-only list of all providers in the stack in the correct order, highest priority first
*/
public List<T> getProviders() {
List<T> l = refresh();
return Collections.unmodifiableList(l);
}
/**
* This allows access to the provider holders
* @return a read only list of the provider holders in the correct order
*/
public List<ProviderHolder<T>> getProviderHolders() {
return Collections.unmodifiableList(providers);
}
/**
* Get the iterator of all providers currently in the stack <br/>
* This will load up lazy so it can be held onto safely but should not be
* used more than once (i.e. only iterate over this completely once, stopping and continuing later is likely to produce failures)
* <br/>
* NOTE: This will attempt to iterate over all the valid providers in the stack but if the provider has been garbage collected
* during the iteration then a {@link NoSuchElementException} will be thrown if the provider was the last one in the
* stack and next() is called, you should probably handle the exception by assuming this indicates all items were iterated over
* @return an iterator over all the providers in the stack in order of priority
*/
public Iterator<T> getIterator() {
return new Iterator<T>() {
protected ListIterator<ProviderHolder<T>> it = null;
public synchronized boolean hasNext() {
if (it == null) {
it = providers.listIterator();
}
return it.hasNext();
}
public synchronized T next() {
if (it == null) {
it = providers.listIterator();
}
/* get the next provider if it is not null, otherwise keep going until we find a non-null one
* or just return null if there are none left
*/
T t = null;
while (it.hasNext()) {
ProviderHolder<T> holder = it.next();
t = holder.getProvider();
if (t != null) {
break;
}
}
if (t == null) {
throw new NoSuchElementException("No more providers remain with valid weak references");
}
return t;
}
public void remove() {
it.remove();
}
};
}
/**
* Get a provider based on the position in the stack (starting at 0 and ending at size-1)
* @param position the position to check for the provider
* @return the provider from the position OR null if there is no provider at that position
*/
public T getProvider(final int position) {
T provider = null;
ProviderHolder<T> holder = getProviderHolder(position);
if (holder != null) {
provider = holder.getProvider();
}
return provider;
}
/**
* Get the provider holder from the position in the stack if there is one
* @param position the position to check for the provider
* @return the holder from the position OR null if there is no provider at that position
*/
public ProviderHolder<T> getProviderHolder(final int position) {
refresh();
ProviderHolder<T> holder;
try {
holder = providers.elementAt(position);
} catch (ArrayIndexOutOfBoundsException e) {
// no provider at that position
holder = null;
}
return holder;
}
/**
* Check the number of current providers which are available in this stack
* @return the total number of viable providers
*/
public int size() {
refresh();
return providers.size();
}
/**
* Delete all providers from the current provider stack
*/
public void clear() {
providers.clear();
}
/**
* Check to make sure all providers are refreshed and any that are no longer valid are flushed out of the list
*/
protected List<T> refresh() {
ArrayList<T> l = new ArrayList<T>();
for (Iterator<ProviderHolder<T>> iterator = providers.iterator(); iterator.hasNext();) {
ProviderHolder<T> holder = iterator.next();
T provider = holder.getProvider();
if (provider == null) {
iterator.remove();
} else {
l.add(provider);
}
}
return l;
}
}

View File

@@ -0,0 +1,48 @@
/**
* $Id: ProviderStackComparator.java 3678 2009-04-06 12:45:44Z grahamtriggs $
* $URL: https://scm.dspace.org/svn/repo/dspace2/core/trunk/utils/src/main/java/org/dspace/utils/servicemanager/ProviderStackComparator.java $
* OrderedBeanComparator.java - DSpace2 - Oct 24, 2008 5:01:44 PM - azeckoski
**************************************************************************
* Copyright (c) 2008 Aaron Zeckoski
* Licensed under the Apache License, Version 2.0
*
* A copy of the Apache License has been included in this
* distribution and is available at: http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (aaron @ caret.cam.ac.uk)
*/
package org.dspace.utils.servicemanager;
import java.util.Comparator;
import java.io.Serializable;
/**
* A comparator for provider stacks, this is specially designed for sorting a list
* of ProviderHolders so it will unpack them and then do the typical sorting on them
* while properly handling the null cases
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public class ProviderStackComparator implements Comparator<ProviderHolder<?>>, Serializable {
public final static long serialVersionUID = 1l;
public int compare(ProviderHolder<?> ph0, ProviderHolder<?> ph1) {
/* a negative integer, zero, or a positive integer as the first argument
* is less than, equal to, or greater than the second.
*/
int comparison = 0;
Object arg0 = ph0.getProvider();
Object arg1 = ph1.getProvider();
if (arg0 == null && arg1 == null) {
comparison = 0;
} else if (arg0 == null) {
comparison = 1; // null is last
} else if (arg1 == null) {
comparison = -1; // null is last
} else {
comparison = new OrderedServiceComparator().compare(arg0, arg1);
}
return comparison;
}
}

Some files were not shown because too many files have changed in this diff Show More