All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.anotheria.anodoc.service.ModuleServiceImpl Maven / Gradle / Ivy

package net.anotheria.anodoc.service;

import net.anotheria.anodoc.data.Module;
import net.anotheria.asg.util.listener.IModuleListener;
import org.configureme.ConfigurationManager;
import org.configureme.annotations.AfterConfiguration;
import org.configureme.annotations.ConfigureMe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * An implementation of IModuleService for local usage,
 * which supports local cache and synchronization over network.
 *
 * @author another
 * @version $Id: $Id
 */
@ConfigureMe (name="anodoc.storage")
public class ModuleServiceImpl implements IModuleService, IModuleListener{

	/**
	 * {@link Logger} instance.
	 */
	private static final Logger LOGGER = LoggerFactory.getLogger(ModuleServiceImpl.class);

	/**
	 * A delimiter which is used between different parts of the unique module key.
	 */
	private static final String DELIMITER = "#";

	/**
	 * Constant used for 'copy' if none is specified.
	 */
	public static final String DEFAULT_COPY_ID = "singlecopy";

	/**
	 * The factories.
	 */
	private Map factories;

	/**
	 * Map with listeners for modules.
	 */
	private Map moduleListeners;

	/**
	 * The module storages.
	 */
	private Map storages;

	/**
	 * The local cache - loaded modules.
	 */
	private Map cache;

	/**
	 * The current instance. ModuleServiceImpl is a Singleton.
	 */
	private static ModuleServiceImpl instance = new ModuleServiceImpl() ;
	
	/**
	 * Returns the current (singleton) instance of this implementation.
	 *
	 * @return a {@link net.anotheria.anodoc.service.ModuleServiceImpl} object.
	 */
	protected static ModuleServiceImpl getInstance(){
		return instance;
	}

	/**
	 * Creates a new ModuleServiceImpl.
	 */
	private ModuleServiceImpl(){
		//initialize local data.
		factories = new ConcurrentHashMap();
		storages  = new ConcurrentHashMap();
		cache = new ConcurrentHashMap();
		moduleListeners = new ConcurrentHashMap();

		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Created new ModuleServiceImplementation");
		}

		ConfigurationManager.INSTANCE.configure(this);
	}

	/**
	 * {@inheritDoc}
	 *
	 * Attaches a factory for given module id.
	 */
	public void attachModuleFactory(String moduleId, IModuleFactory factory) {
		factories.put(moduleId, factory);
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Attached module factory "+factory+" for moduleId:"+moduleId);
		}
	}
	
	/**
	 * {@inheritDoc}
	 *
	 * Attaches a storage for given module id.
	 */
	public void attachModuleStorage(String moduleId, IModuleStorage storage){

		storages.put(moduleId, storage);
		storage.addModuleListener(this);

		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Attached module storage "+storage+" for moduleId:"+moduleId);
		}
	}

	/**
	 * Puts the module into local cache. 
	 */	
	private void putInCache(Module module){
		String key = getKey(module);
		cache.put(key, module);
	}

	/**
	 * Removes the module from cache.
	 */	
	private void removeFromCache(String moduleId, String ownerId, String copyId){
		String key = getKey(moduleId,copyId, ownerId);
		cache.remove(key);
	}

	/**
	 * Returns module from.
	 * @param module module to serch in cache.
	 * @return module if it was in cache, otherwise null.
	 */
	private Module getModuleFromCache(Module module) {
		String key = getKey(module);
		Module cachedModule = cache.get(key);

		return cachedModule;
	}

	/**
	 * Put in cache and store.
	 */
	private void putInCacheDirty(Module module) throws NoStorageForModuleException, StorageFailureException{
		putInCache(module);
		IModuleStorage storage = storages.get(module.getId());
		if (storage==null){
			LOGGER.warn("No storage for " + module.getId() + ", " + module + " is not persistent!");
			throw new NoStorageForModuleException(module.getId());
		}
		storage.saveModule(module);
	}
	
	/**
	 * Removes the given module tuple from cache AND storage. 
	 */
	private void removeFromCacheDirty(String moduleId, String ownerId, String copyId) throws NoStorageForModuleException, StorageFailureException{
		removeFromCache(moduleId, ownerId, copyId)	;
		IModuleStorage storage = storages.get(moduleId);
		if (storage==null){
			throw new NoStorageForModuleException(moduleId);
		}
		storage.deleteModule(ownerId, copyId);
	}

	/**
	 * {@inheritDoc}
	 *
	 * Same as getModule(ownerId, moduleId, copyId, false)
	 */
	public Module getModule(String ownerId, String moduleId, String copyId) 
			throws NoStorageForModuleException, NoFactoryForModuleException, NoStoredModuleEntityException, StorageFailureException{
		return getModule(ownerId, moduleId, copyId, false);
	}

	/**
	 * {@inheritDoc}
	 *
	 * Same as getModule(ownerId, moduleId, default_copy_id, false)
	 */
	public Module getModule(String ownerId, String moduleId) 
			throws NoStorageForModuleException, NoFactoryForModuleException, NoStoredModuleEntityException, StorageFailureException{
		return getModule(ownerId, moduleId, DEFAULT_COPY_ID, false);
	}

	/**
	 * Same as getModule(ownerId, moduleId, default_copy_id, create?)
	 *
	 * @param ownerId a {@link java.lang.String} object.
	 * @param moduleId a {@link java.lang.String} object.
	 * @param create a boolean.
	 * @return a {@link net.anotheria.anodoc.data.Module} object.
	 * @throws net.anotheria.anodoc.service.NoStorageForModuleException if any.
	 * @throws net.anotheria.anodoc.service.NoFactoryForModuleException if any.
	 * @throws net.anotheria.anodoc.service.NoStoredModuleEntityException if any.
	 * @throws net.anotheria.anodoc.service.StorageFailureException if any.
	 */
	public Module getModule(
		String ownerId,
		String moduleId,
		boolean create) 
			throws NoStorageForModuleException, NoFactoryForModuleException, NoStoredModuleEntityException, StorageFailureException{
		return getModule(ownerId, moduleId, DEFAULT_COPY_ID, create);
	}
	

	/** {@inheritDoc} */
	@Override public Module getModule(
		String ownerId,
		String moduleId,
		String copyId,
		boolean create) 
			throws NoStorageForModuleException, NoFactoryForModuleException, NoStoredModuleEntityException, StorageFailureException{
		
		
		String key = getKey(moduleId, copyId, ownerId);
		//System.out.println("getModule() "+key+" called");

		
		//first we check if we have this module in cache.
		Module module = cache.get(key);
		
		if (module!=null){
			LOGGER.debug("Module " + key + " was in cache");
			return module;
		}
		
		
		try{
			LOGGER.debug("Trying to load module from storage:" + key);
			module = loadModule(moduleId, ownerId, copyId);
			//System.out.println("Loading from disk.");
			LOGGER.debug("Loaded module from storage.");
			putInCache(module);
			//long en = System.currentTimeMillis();
			return module;
		}catch(NoStoredModuleEntityException e){
			//log.debug("Loading failed:",e);
			if (create){
				LOGGER.debug("Creating new instance of " + moduleId + ", " + ownerId + ", " + copyId);
				//eigentlich sollte das die factory schon tun,
				//aber sicher ist sicher, oder?	 :-)
				//interessant, wer wird diesen kommentar lesen? schreibt mal
				//was zurueck, ich fand diskussionen ueber kommentare immer lustig.
				module = createModule(moduleId, ownerId, copyId); 
				module.setOwnerId(ownerId);
				module.setCopyId(copyId);
				putInCacheDirty(module);
				return module;
			}
			
			LOGGER.debug("Loading failed:", e);
			throw e;
			
		}
	}

	/**
	 * Loads the module identified by the tuple from the storage. If there is no 
	 * storage for this moduleId a NoStorageForModuleException will be thrown.
	 */	
	private Module loadModule(String moduleId, String ownerId, String copyId) throws NoStorageForModuleException, NoStoredModuleEntityException, StorageFailureException{
		IModuleStorage storage = storages.get(moduleId);
		if (storage==null){
			throw new NoStorageForModuleException(moduleId);
		}
		return storage.loadModule(ownerId, copyId);
	}

	/**
	 * Creates a new instance of the specified module using the attached factory. 
	 */	
	private Module createModule(String moduleId, String ownerId, String copyId) throws NoFactoryForModuleException{
		IModuleFactory factory = factories.get(moduleId);
		if (factory==null){
			throw new NoFactoryForModuleException(moduleId);
		}
		return factory.createModule(ownerId, copyId);
	}

	/** {@inheritDoc} */
	@Override public void storeModule(Module module) throws NoStorageForModuleException, StorageFailureException{
		try{
			LockHolder.prepareForSave();
			putInCacheDirty(module);
		}finally{
			LockHolder.notifySaved();
		}
	}
	
	/**
	 * Returns the cache key for given tuple. 
	 */
	private String getKey(String moduleId, String copyId, String ownerId){
		return copyId+DELIMITER+moduleId+DELIMITER+ownerId;
	}
	
	/**
	 * Returns the cache key for given module. 
	 */
	private String getKey(Module module){
		return getKey(module.getId(), module.getCopyId(), module.getOwnerId());
	}

	/** {@inheritDoc} */
	@Override public void deleteModule(Module module) throws NoStorageForModuleException, StorageFailureException{
		deleteModule(module.getOwnerId(), module.getId(), module.getCopyId());
	}

	/** {@inheritDoc} */
	@Override public void deleteModule(String ownerId, String moduleId, String copyId)
		throws NoStorageForModuleException , StorageFailureException{
		removeFromCacheDirty(moduleId, ownerId, copyId);
		
	}

	/** {@inheritDoc} */
	@Override public void deleteModule(String ownerId, String moduleId)
		throws NoStorageForModuleException , StorageFailureException{
		deleteModule(ownerId, moduleId, DEFAULT_COPY_ID);
	}


	/**
	 * {@inheritDoc}
	 *
	 * Removes changed module from cache and fires moduleLoaded event of registered listener.
	 */
	@Override
	public void moduleLoaded(Module module){
		LOGGER.info("Persistence changed for " + module);
		removeFromCache(module.getId(),module.getOwnerId(),module.getCopyId());

		IModuleListener listener = moduleListeners.get(getKey(module.getId(), DEFAULT_COPY_ID, module.getOwnerId()));
		if (listener!=null)
			try{
				listener.moduleLoaded(module);
			}catch(Exception e){
				LOGGER.warn("Caught uncaught exception by the listener " + listener + ", contentChanged()", e);
			}
	}

	/** {@inheritDoc} */
	@Override
	public void addModuleListener(String moduleId, String ownerId, IModuleListener aModuleListeners){
		String key = getKey(moduleId, DEFAULT_COPY_ID, ownerId);

		moduleListeners.put(key, aModuleListeners);
	}

	/**
	 * {@inheritDoc}
	 *
	 * Removes listener for module.
	 */
	@Override
	public void removeModuleListener(String moduleId, String ownerId) {
		moduleListeners.remove(getKey(moduleId, DEFAULT_COPY_ID, ownerId));
	}

	/**
	 * 

notifyConfigurationFinished.

*/ @AfterConfiguration public void notifyConfigurationFinished() { LOGGER.info("Cleaning cache."); cache.clear(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy