/*******************************************************************************
* Imixs Workflow
* Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,
* http://www.imixs.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html
*
* Project:
* http://www.imixs.org
* http://java.net/projects/imixs-workflow
*
* Contributors:
* Imixs Software Solutions GmbH - initial API and implementation
* Ralph Soika - Software Developer
*******************************************************************************/
package org.imixs.marty.ejb;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Singleton;
import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.ItemCollectionComparator;
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.exceptions.AccessDeniedException;
import org.imixs.workflow.exceptions.InvalidAccessException;
import org.imixs.workflow.exceptions.QueryException;
/**
* The Marty Config Service can be used to store and access configuration values
* stored in a configuration entity (type='CONFIGURATION).
*
* The ConfigService EJB provides access to named Config Entities stored in the
* database. A configuration Entity is identified by its name (property
* txtName). So different configuration Entities can be managed in one
* application.
*
* The ConfigService ejb is implemented as a sigelton and uses an internal cache
* to cache config entities.
*
*
* @author rsoika
*/
@DeclareRoles({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS",
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@RolesAllowed({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS",
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@Singleton
public class ConfigService {
int DEFAULT_CACHE_SIZE = 30;
@EJB
private DocumentService documentService;
private Cache cache = null;
final String TYPE = "configuration";
/**
* PostContruct event - loads the imixs.properties.
*/
@PostConstruct
void init() {
// initialize cache
cache = new Cache(DEFAULT_CACHE_SIZE);
}
/**
* creates a new configuration object for a specified name
*
* @return
*/
public ItemCollection createConfiguration(String name) throws Exception {
ItemCollection configItemCollection = new ItemCollection();
configItemCollection.replaceItemValue("type", TYPE);
configItemCollection.replaceItemValue("txtname", name);
configItemCollection.replaceItemValue("$writeAccess", "org.imixs.ACCESSLEVEL.MANAGERACCESS");
configItemCollection.replaceItemValue("$readAccess", "");
cache.put(name, configItemCollection);
return configItemCollection;
}
/**
* This method deletes an existing Configuration.
*
* @param aconfig
* @throws AccessDeniedException
*/
public void deleteConfiguration(ItemCollection aconfig) throws AccessDeniedException {
cache.remove(aconfig.getItemValueString("txtName"));
documentService.remove(aconfig);
}
/**
* This method returns a config ItemCollection for a specified name. If no
* configuration is found for this name the Method creates an empty
* configuration object. The config entity is cached internally and read
* from the cache
*
* @param name
* in attribute txtname
*
*/
public ItemCollection loadConfiguration(String name) {
return this.loadConfiguration(name, false);
}
/**
* This method returns a config ItemCollection for a specified name. If no
* configuration is found for this name the Method creates an empty
* configuration object. The config entity is cached internally.
*
* @param name
* in attribute txtname
*
* @param discardCache
* - indicates if the internal cache should be discarded.
*/
public ItemCollection loadConfiguration(String name, boolean discardCache) {
ItemCollection configItemCollection = null;
// check cache...
configItemCollection = cache.get(name);
if (configItemCollection == null || discardCache) {
String sQuery="(type:\"" + TYPE + "\" AND txtname:\""+name + "\")";
Collection<ItemCollection> col;
try {
col = documentService.find(sQuery, 1, 0);
} catch (QueryException e) {
throw new InvalidAccessException(InvalidAccessException.INVALID_ID,e.getMessage(),e);
}
if (col.size() > 0) {
configItemCollection = col.iterator().next();
} else {
// create default values
configItemCollection = new ItemCollection();
configItemCollection.replaceItemValue("type", TYPE);
configItemCollection.replaceItemValue("txtname", name);
}
cache.put(name, configItemCollection);
}
return configItemCollection;
}
/**
* save the configuration entity
*
* @return
* @throws AccessDeniedException
*/
public ItemCollection save(ItemCollection configItemCollection) throws AccessDeniedException {
// update write and read access
configItemCollection.replaceItemValue("type", TYPE);
// save entity
configItemCollection = documentService.save(configItemCollection);
cache.put(configItemCollection.getItemValueString("txtName"), configItemCollection);
return configItemCollection;
}
/**
* Returns a list of all configuration entities.
*
* @return
*/
public List<ItemCollection> findAllConfigurations() {
ArrayList<ItemCollection> configList = new ArrayList<ItemCollection>();
// String sQuery = "SELECT orgunit FROM Entity AS orgunit " + " JOIN orgunit.textItems AS t2"
// + " WHERE orgunit.type = '" + TYPE + "'" + " AND t2.itemName = 'txtname'"
// + " ORDER BY t2.itemValue asc";
Collection<ItemCollection> col = documentService.getDocumentsByType(TYPE);
for (ItemCollection aworkitem : col) {
configList.add(aworkitem);
}
// sort by txtname
Collections.sort(configList, new ItemCollectionComparator("txtname", true));
return configList;
}
/**
* Cache implementation to hold config entities
*
* @author rsoika
*
*/
class Cache extends LinkedHashMap<String, ItemCollection> implements Serializable {
private static final long serialVersionUID = 1L;
private final int capacity;
public Cache(int capacity) {
super(capacity + 1, 1.1f, true);
this.capacity = capacity;
}
protected boolean removeEldestEntry(Entry<String, ItemCollection> eldest) {
return size() > capacity;
}
}
}