/**
* Copyright (c) 2004-2011 Wang Jinbao(Julian Wong), http://www.ralasafe.com
* Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
*/
package org.ralasafe.entitle;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ralasafe.EntityExistException;
import org.ralasafe.Factory;
import org.ralasafe.RalasafeException;
import org.ralasafe.SystemConstant;
import org.ralasafe.db.DBLevelException;
import org.ralasafe.db.DBPower;
import org.ralasafe.db.JavaBeanColumnAdapter;
import org.ralasafe.db.JavaBeanObjectNewer;
import org.ralasafe.db.SelectCondition;
import org.ralasafe.db.Table;
import org.ralasafe.db.TableNewer;
import org.ralasafe.db.impl.TableDeletorImpl;
import org.ralasafe.db.impl.TableSaverImpl;
import org.ralasafe.db.impl.TableSelectorImpl;
import org.ralasafe.db.impl.TableUpdatorImpl;
import org.ralasafe.db.sql.xml.BusinessDataList;
import org.ralasafe.group.Node;
import org.ralasafe.script.ScriptFactory;
import org.ralasafe.user.User;
import org.ralasafe.util.DBUtil;
import org.ralasafe.util.IOUtil;
import org.ralasafe.util.StringUtil;
public class BusinessDataManagerImpl implements BusinessDataManager {
private static final int ROOT_ID = 0;
private static String storeDir = SystemConstant.getBusinessDataStoreDir();
/** key/value=id<Integer>/businessData<org.ralasafe.entitle.BusinessData> */
private Map storeMap;
private String appName;
private Table table;
private TableSelectorImpl selector;
private TableSaverImpl saver;
private TableUpdatorImpl updator;
private TableDeletorImpl deleter;
private Comparator comp;
private String storeFilePostfix;
private static Log log=LogFactory.getLog( BusinessDataManagerImpl.class );
public BusinessDataManagerImpl(String appName) {
this.appName = appName;
storeFilePostfix = "_" + appName + ".xml";
storeMap = new HashMap();
//
TableNewer tableNewer = new TableNewer();
tableNewer.setTableName(appName + "_businessdata");
tableNewer.setColumnNames(new String[] { "id", "name", "description",
"installDate", "fileName", "pid", "isLeaf" });
tableNewer.setIdColumnNames(new String[] { "id" });
tableNewer.setUniqueColumnNames(new String[] { "name" });
tableNewer.setMappingClass(BusinessData.class.getName());
tableNewer.put("id", new JavaBeanColumnAdapter("id", "int"));
tableNewer.put("name", new JavaBeanColumnAdapter("name",
"java.lang.String"));
tableNewer.put("description", new JavaBeanColumnAdapter("description",
"java.lang.String"));
tableNewer.put("installDate", new JavaBeanColumnAdapter("installDate",
"java.util.Date"));
tableNewer.put("fileName", new JavaBeanColumnAdapter("file",
"java.lang.String"));
tableNewer.put("pid", new JavaBeanColumnAdapter("pid", "int"));
tableNewer
.put("isLeaf", new JavaBeanColumnAdapter("isLeaf", "boolean"));
tableNewer.setId(DBPower.getTableId(null, tableNewer.getTableName()));
table = tableNewer.getTable();
selector = new TableSelectorImpl();
selector.setObjectNewer(new JavaBeanObjectNewer(tableNewer
.getMappingClass()));
saver = new TableSaverImpl();
updator = new TableUpdatorImpl();
deleter = new TableDeletorImpl();
selector.setTable(table);
saver.setTable(table);
updator.setTable(table);
deleter.setTable(table);
comp = new Comparator() {
public int compare(Object o1, Object o2) {
BusinessData q1 = (BusinessData) o1;
BusinessData q2 = (BusinessData) o2;
return q1.getName().compareTo(q2.getName());
}
};
// load all definitions
loadIntoMemory();
}
public Collection checkSameNameBusinessData(String fileUrl) {
try {
BusinessDataList root = BusinessDataList.unmarshal(new FileReader(
fileUrl));
org.ralasafe.db.sql.xml.BusinessData[] xmlDataList = root
.getBusinessData();
return checkSameNameBusinessData(xmlDataList);
} catch (Exception e) {
log.error( "", e );
throw new RalasafeException(e);
}
}
private Collection checkSameNameBusinessData(
org.ralasafe.db.sql.xml.BusinessData[] dataList) {
// put to be checked name into set
Set toCheckNames = new HashSet();
for (int i = 0; i < dataList.length; i++) {
String name = dataList[i].getName();
toCheckNames.add(name);
}
// compare every node name in store with toCheckNames
List sameNames = new ArrayList(dataList.length);
for (Iterator iter = storeMap.values().iterator(); iter.hasNext();) {
BusinessData data = (BusinessData) iter.next();
String name = data.getName();
if (data.getIsLeaf() && toCheckNames.contains(name)) {
sameNames.add(name);
}
}
return sameNames;
}
public void installBusinessData(String fileUrl, boolean overwrite) {
Connection conn = null;
try {
conn = DBPower.getConnection(table.getId());
BusinessDataList root = BusinessDataList.unmarshal(new FileReader(
fileUrl));
org.ralasafe.db.sql.xml.BusinessData[] xmlDataList = root
.getBusinessData();
List saveUcs = new ArrayList(xmlDataList.length);
Collection sameNames = checkSameNameBusinessData(xmlDataList);
Set sameNameSet = new HashSet();
sameNameSet.addAll(sameNames);
for (int i = 0; i < xmlDataList.length; i++) {
org.ralasafe.db.sql.xml.BusinessData xmlData = xmlDataList[i];
String name = xmlData.getName();
java.io.StringWriter xmlContentWriter = new java.io.StringWriter();
xmlData.marshal(xmlContentWriter);
BusinessData data = new BusinessData();
data.setName(name);
data.setXmlContent(xmlContentWriter.toString());
data.setInstallDate(new Date());
data.setPid(ROOT_ID);// AS a child of ROOT node
data.setIsLeaf(true);
if (sameNameSet.contains(name)) {
if (overwrite) {
// update this BusinessData
BusinessData orginal = getBusinessData(name);
data.setId(orginal.getId());
data.setFile(data.getId() + storeFilePostfix);
data.setIsLeaf(orginal.getIsLeaf());
data.setPid(orginal.getPid());
updator.updateByIdColumns(data);
}
} else {
data.setId(newBusinessDataId());
data.setFile(data.getId() + storeFilePostfix);
saveUcs.add(data);
}
// write xml content into file system
String storeFile = storeDir + data.getFile();
IOUtil.write(storeFile, data.getXmlContent());
}
saver.batchSave(conn, saveUcs);
// definition changed, reload
loadIntoMemory();
} catch (DBLevelException e) {
log.error( "", e );
try {
conn.rollback();
} catch (SQLException e1) {
throw new RalasafeException(e1);
}
throw new RalasafeException(e);
} catch (IOException e) {
log.error( "", e );
try {
conn.rollback();
} catch (SQLException e1) {
throw new RalasafeException(e1);
}
throw new RalasafeException(e);
} catch (Exception e) {
log.error( "", e );
throw new RalasafeException(e);
} finally {
DBUtil.close(conn);
}
}
public Collection getLikelyBusinessData(String name) {
List result = new LinkedList();
for (Iterator iter = storeMap.values().iterator(); iter.hasNext();) {
BusinessData businessData = (BusinessData) iter.next();
String businessDataName = businessData.getName();
if (businessDataName.indexOf(name) > -1) {
result.add(businessData);
}
}
return result;
}
public BusinessData getBusinessData(String name) {
for (Iterator iter = storeMap.values().iterator(); iter.hasNext();) {
BusinessData businessData = (BusinessData) iter.next();
String businessDataName = businessData.getName();
if (businessDataName.equals(name)) {
return businessData;
}
}
return null;
}
private int newBusinessDataId() {
try {
int id = DBUtil.getSequenceNextVal(table, "id");
// we need id>0
while (id <= 0) {
id = DBUtil.getSequenceNextVal(table, "id");
}
return id;
} catch (SQLException e) {
throw new DBLevelException(e);
}
}
/**
* Load BusinessData definitions from database into memory.
*/
private synchronized void loadIntoMemory() {
Collection businessDataList = selector.select(new SelectCondition(),
null);
storeMap.clear();
for (Iterator iter = businessDataList.iterator(); iter.hasNext();) {
BusinessData businessData = (BusinessData) iter.next();
if (businessData.getIsLeaf()) {
loadXmlContent(businessData);
}
storeMap.put(new Integer(businessData.getId()), businessData);
}
// build tree
// first, add a root node
BusinessData root = new BusinessData();
root.setId(ROOT_ID);
root.setPid(-1);
root.setName("root");
root.setIsLeaf(false);
storeMap.put(new Integer(ROOT_ID), root);
for (Iterator iter = businessDataList.iterator(); iter.hasNext();) {
BusinessData current = (BusinessData) iter.next();
// set parent
int pid = current.getPid();
BusinessData pNode = (BusinessData) storeMap.get(new Integer(pid));
current.setParent(pNode);
// set as a child
if (pNode != null) {
Collection children = pNode.getChildren();
if (children == null) {
children = new LinkedList();
pNode.setChildren(children);
}
children.add(current);
}
}
}
private void loadXmlContent(BusinessData businessData) {
// Read file system to receive xml content
String file = businessData.getFile();
if (!StringUtil.isEmpty(file)) {
String storeFile = storeDir + file;
try {
String content = IOUtil.read(storeFile);
businessData.setXmlContent(content);
} catch (IOException e) {
log.error( "", e );
throw new RalasafeException(e);
}
}
String xmlContent = businessData.getXmlContent();
if (!StringUtil.isEmpty(xmlContent)) {
org.ralasafe.db.sql.xml.BusinessDataType xmlBusinessData;
try {
xmlBusinessData = org.ralasafe.db.sql.xml.BusinessData
.unmarshal(new StringReader(xmlContent));
} catch (Exception e) {
log.error( "", e );
throw new RalasafeException(e);
}
org.ralasafe.script.BusinessData scriptBusinessData = ScriptFactory
.getBusinessData(xmlBusinessData, Factory
.getQueryManager(appName));
businessData.setScriptBusinessData(scriptBusinessData);
}
}
/**
* Remove xml head like <?xml version="1.0" encoding="UTF-8"?>
*/
private String removeXMLHead(String xml) {
int index = xml.indexOf("?>");
if (index > 0)
return xml.substring(index + 2);
else
return xml;
}
public Collection getAllBusinessData() {
Collection values = storeMap.values();
List result = new ArrayList(values.size());
result.addAll(values);
Collections.sort(result, comp);
return result;
}
public BusinessData addBusinessData(int pid, String name,
String description, boolean isLeaf) throws EntityExistException {
if (isLeaf) {
return addLeafBusinessData(pid, name, description);
} else {
return addBranchBusinessData(pid, name, description);
}
}
private BusinessData addLeafBusinessData(int pId, String name,
String description) throws EntityExistException {
BusinessData businessData = new BusinessData();
businessData.setId(newBusinessDataId());
businessData.setName(name);
businessData.setDescription(description);
businessData.setInstallDate(new Date());
businessData.setPid(pId);
businessData.setIsLeaf(true);
businessData.setXmlContent(initXmlContent(name, description));
businessData.setFile(businessData.getId() + storeFilePostfix);
// Write to file system
String file = storeDir + businessData.getFile();
try {
IOUtil.write(file, businessData.getXmlContent());
} catch (IOException e) {
log.error( "", e );
throw new RalasafeException(e);
}
saver.save(businessData);
// update cache
loadXmlContent(businessData);
BusinessData parent = (BusinessData) storeMap.get(new Integer(
businessData.getPid()));
businessData.setParent(parent);
parent.getChildren().add(businessData);
storeMap.put(new Integer(businessData.getId()), businessData);
return businessData;
}
private BusinessData addBranchBusinessData(int pid, String name,
String description) throws DBLevelException, EntityExistException {
BusinessData businessData = new BusinessData();
businessData.setId(newBusinessDataId());
businessData.setName(name);
businessData.setDescription(description);
businessData.setInstallDate(new Date());
businessData.setPid(pid);
businessData.setIsLeaf(false);
saver.save(businessData);
// update cache
BusinessData parent = (BusinessData) storeMap.get(new Integer(
businessData.getPid()));
businessData.setParent(parent);
parent.getChildren().add(businessData);
storeMap.put(new Integer(businessData.getId()), businessData);
return businessData;
}
private String initXmlContent(String name, String description) {
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \r\n"
+"<businessData name=\"" + name +
"\" isRawScript=\"false\">\r\n"
+" <exprGroup linker=\"AND\"/> \r\n"
+" <rawScript> \r\n"
+" <content></content> \r\n"
+" </rawScript> \r\n"
+"</businessData>";
}
public void deleteBusinessData(int id) {
// Check cache store
BusinessData businessData = (BusinessData) storeMap
.get(new Integer(id));
if (businessData == null) {
return;
}
if (businessData.getIsLeaf()) {
deleteSingleBusinessData(id);
} else {
Collection children = businessData.getChildren();
Iterator itr = children.iterator();
int[] ids = new int[children.size()];
for (int i = 0; i < ids.length; i++) {
BusinessData child = (BusinessData) itr.next();
ids[i] = child.getId();
}
for (int i = 0; i < ids.length; i++) {
deleteBusinessData(ids[i]);
}
deleteSingleBusinessData(id);
}
}
private void deleteSingleBusinessData(int id) {
BusinessData hint = new BusinessData();
hint.setId(id);
deleter.deleteByIdColumns(hint);
// delete cascade things
EntitleManager entitleManager = Factory.getEntitleManager(appName);
entitleManager.deleteCascadeEntitlementByBusinessData(id);
// remove xml file
BusinessData businessData = (BusinessData) storeMap
.get(new Integer(id));
if (businessData != null && !StringUtil.isEmpty(businessData.getFile())) {
new File(storeDir + businessData.getFile()).delete();
}
// update cache
BusinessData parent = (BusinessData) storeMap.get(new Integer(
businessData.getPid()));
businessData.setParent(null);
businessData.setChildren(null);
parent.getChildren().remove(businessData);
storeMap.remove(new Integer(businessData.getId()));
}
public BusinessData getBusinessData(int id) {
return (BusinessData) storeMap.get(new Integer(id));
}
public void updateBusinessData(int id, String name, String description)
throws EntityExistException {
BusinessData original = getBusinessData(id);
if (original == null) {
return;
}
original.setName(name);
original.setDescription(description);
updator.updateByIdColumns(original);
String xmlContent=original.getXmlContent();
if( StringUtil.isEmpty( xmlContent ) ) {
// no xml content to be updated
return;
}
org.ralasafe.db.sql.xml.BusinessDataType xmlData;
try {
xmlData = org.ralasafe.db.sql.xml.BusinessData
.unmarshal(new StringReader( xmlContent ));
} catch (Exception e) {
log.error( "", e );
throw new RalasafeException(e);
}
xmlData.setName( name );
updateBusinessData( id, (org.ralasafe.db.sql.xml.BusinessData)xmlData );
}
public void updateBusinessData(int id,
org.ralasafe.db.sql.xml.BusinessData content)
throws EntityExistException {
BusinessData original = getBusinessData(id);
if (original == null) {
return;
}
java.io.StringWriter xmlContentWriter = new java.io.StringWriter();
try {
content.marshal(xmlContentWriter);
} catch (Exception e) {
log.error( "", e );
throw new RalasafeException(e);
}
original.setXmlContent(xmlContentWriter.toString());
// Update xml file
String file = storeDir + original.getFile();
try {
IOUtil.write(file, StringUtil.keepSpaceInContent(original
.getXmlContent(), content.getRawScript().getContent()));
} catch (IOException e) {
log.error( "", e );
throw new RalasafeException(e);
}
// update cache
loadXmlContent(original);
}
public BusinessData copyBusinessData(int sourceId, String newName,
String newDescription) throws EntityExistException {
BusinessData original = getBusinessData(sourceId);
if (original == null) {
String msg="No business data found to copy.";
log.error( msg );
throw new RalasafeException(msg);
}
if (!original.getIsLeaf()) {
throw new RalasafeException("Can not copy business data group.");
}
BusinessData businessData = new BusinessData();
businessData.setId(newBusinessDataId());
businessData.setName(newName);
businessData.setDescription(newDescription);
businessData.setInstallDate(new Date());
businessData.setFile(businessData.getId() + storeFilePostfix);
businessData.setPid(original.getPid());
businessData.setIsLeaf(original.getIsLeaf());
if (businessData.getIsLeaf()) {
// update xml content (only name attribute been changed)
String file = original.getFile();
if (!StringUtil.isEmpty(file)) {
String storeFile = storeDir + file;
try {
String content = IOUtil.read(storeFile);
businessData.setXmlContent(content);
} catch (IOException e) {
log.error( "", e );
throw new RalasafeException(e);
}
}
String xmlContent = businessData.getXmlContent();
if (!StringUtil.isEmpty(xmlContent)) {
org.ralasafe.db.sql.xml.BusinessDataType xmlBusinessData;
try {
xmlBusinessData = org.ralasafe.db.sql.xml.BusinessData
.unmarshal(new StringReader(xmlContent));
xmlBusinessData.setName(businessData.getName());
java.io.StringWriter xmlContentWriter = new java.io.StringWriter();
try {
xmlBusinessData.marshal(xmlContentWriter);
} catch (Exception e) {
log.error( "", e );
throw new RalasafeException(e);
}
businessData.setXmlContent(xmlContentWriter
.toString());
// update to file system
file = storeDir + businessData.getFile();
IOUtil.write(file, StringUtil.keepSpaceInContent(
businessData.getXmlContent(), xmlBusinessData
.getRawScript().getContent()));
} catch (Exception e) {
log.error( "", e );
throw new RalasafeException(e);
}
}
}
saver.save(businessData);
// update cache
loadXmlContent(businessData);
BusinessData parent = (BusinessData) storeMap.get(new Integer(
businessData.getPid()));
businessData.setParent(parent);
parent.getChildren().add(businessData);
storeMap.put(new Integer(businessData.getId()), businessData);
return businessData;
}
public BusinessData getBusinessDataTree() {
return getBusinessData(ROOT_ID);
}
public void moveBusinessData(int id, int newPid) {
try {
BusinessData businessData = getBusinessData(id);
BusinessData oldParent = getBusinessData(businessData.getPid());
BusinessData newParent = getBusinessData(newPid);
if (newParent.getIsLeaf()) {
throw new RalasafeException("The target node may not be a leaf.");
}
if (businessData == newParent
|| isCascadeChild(businessData.getId(), newParent.getId())) {
throw new RalasafeException("This node noving will produce a cycle.");
}
// update this node
businessData.setPid(newParent.getId());
updator.updateByIdColumns(businessData);
// update cache
businessData.setParent(newParent);
oldParent.getChildren().remove(businessData);
newParent.getChildren().add(businessData);
} catch (EntityExistException e) {
log.error( "", e );
throw new RalasafeException(e);
}
}
private boolean isCascadeChild(int pId, int id) {
Node parent = getBusinessData(pId);
Node child = getBusinessData(id);
if (parent != null && child != null) {
while (child.getParent() != null) {
if (parent == child.getParent())
return true;
else
child = child.getParent();
}
}
return false;
}
public BusinessDataTestResult testBusinessData(
org.ralasafe.script.BusinessData scriptBusinessData, User user,
Map context) {
QueryManager queryManager = Factory.getQueryManager(appName);
return scriptBusinessData.test(user, context, queryManager);
}
}