package railo.runtime.orm;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import railo.commons.io.SystemUtil;
import railo.commons.lang.StringUtil;
import railo.commons.lang.SystemOut;
import railo.runtime.Component;
import railo.runtime.ComponentPro;
import railo.runtime.PageContext;
import railo.runtime.PageContextImpl;
import railo.runtime.component.Property;
import railo.runtime.config.ConfigImpl;
import railo.runtime.config.Constants;
import railo.runtime.db.DataSource;
import railo.runtime.engine.ThreadLocalPageContext;
import railo.runtime.exp.PageException;
import railo.runtime.listener.ApplicationContextPro;
import railo.runtime.op.Caster;
import railo.runtime.op.Decision;
import railo.runtime.op.Operator;
import railo.runtime.orm.hibernate.ExceptionUtil;
import railo.runtime.type.Collection;
import railo.runtime.type.Collection.Key;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.util.KeyConstants;
import railo.runtime.type.util.ListUtil;
public class ORMUtil {
public static ORMSession getSession(PageContext pc) throws PageException {
return getSession(pc,true);
}
public static ORMSession getSession(PageContext pc, boolean create) throws PageException {
return ((PageContextImpl) pc).getORMSession(create);
}
public static ORMEngine getEngine(PageContext pc) throws PageException {
ConfigImpl config=(ConfigImpl) pc.getConfig();
return config.getORMEngine(pc);
}
/**
*
* @param pc
* @param force if set to false the engine is on loaded when the configuration has changed
* @throws PageException
*/
public static void resetEngine(PageContext pc, boolean force) throws PageException {
ConfigImpl config=(ConfigImpl) pc.getConfig();
config.resetORMEngine(pc,force);
}
public static void printError(Throwable t, ORMEngine engine) {
printError(t, engine, t.getMessage());
}
public static void printError(String msg, ORMEngine engine) {
printError(null, engine, msg);
}
public static void printError(Throwable t) {
printError(t, null, t.getMessage());
}
public static void printError(String msg) {
printError(null, null, msg);
}
private static void printError(Throwable t, ORMEngine engine,String msg) {
if(engine!=null)SystemOut.printDate("{"+engine.getLabel().toUpperCase()+"} - "+msg,SystemUtil.ERR);
else SystemOut.printDate(msg, SystemUtil.ERR);
if(t==null)t=new Throwable();
t.printStackTrace(SystemOut.getPrinWriter(SystemUtil.ERR));
}
public static boolean equals(Object left, Object right) {
HashSet<Object> done=new HashSet<Object>();
return _equals(done, left, right);
}
private static boolean _equals(HashSet<Object> done,Object left, Object right) {
if(left==right) return true;
if(left==null || right==null) return false;
// components
if(left instanceof Component && right instanceof Component){
return _equals(done,(Component)left, (Component)right);
}
// arrays
if(Decision.isArray(left) && Decision.isArray(right)){
return _equals(done,Caster.toArray(left,null), Caster.toArray(right,null));
}
// struct
if(Decision.isStruct(left) && Decision.isStruct(right)){
return _equals(done,Caster.toStruct(left,null), Caster.toStruct(right,null));
}
try {
return Operator.equals(left,right,false);
} catch (PageException e) {
return false;
}
}
private static boolean _equals(HashSet<Object> done,Collection left, Collection right) {
if(done.contains(left)) return done.contains(right);
done.add(left);
done.add(right);
if(left.size()!=right.size()) return false;
//Key[] keys = left.keys();
Iterator<Entry<Key, Object>> it = left.entryIterator();
Entry<Key, Object> e;
Object l,r;
while(it.hasNext()){
e = it.next();
l=e.getValue();
r=right.get(e.getKey(),null);
if(r==null || !_equals(done,l, r)) return false;
}
return true;
}
private static boolean _equals(HashSet<Object> done,Component left, Component right) {
if(done.contains(left)) return done.contains(right);
done.add(left);
done.add(right);
if(left==null || right==null) return false;
if(!left.getPageSource().equals(right.getPageSource())) return false;
Property[] props = getProperties(left);
Object l,r;
props=getIds(props);
for(int i=0;i<props.length;i++){
l=left.getComponentScope().get(KeyImpl.init(props[i].getName()),null);
r=right.getComponentScope().get(KeyImpl.init(props[i].getName()),null);
if(!_equals(done,l, r)) return false;
}
return true;
}
public static Property[] getIds(Property[] props) {
ArrayList<Property> ids=new ArrayList<Property>();
for(int y=0;y<props.length;y++){
String fieldType = Caster.toString(props[y].getDynamicAttributes().get(KeyConstants._fieldtype,null),null);
if("id".equalsIgnoreCase(fieldType) || ListUtil.listFindNoCaseIgnoreEmpty(fieldType,"id",',')!=-1)
ids.add(props[y]);
}
// no id field defined
if(ids.size()==0) {
String fieldType;
for(int y=0;y<props.length;y++){
fieldType = Caster.toString(props[y].getDynamicAttributes().get(KeyConstants._fieldtype,null),null);
if(StringUtil.isEmpty(fieldType,true) && props[y].getName().equalsIgnoreCase("id")){
ids.add(props[y]);
props[y].getDynamicAttributes().setEL(KeyConstants._fieldtype, "id");
}
}
}
// still no id field defined
if(ids.size()==0 && props.length>0) {
String owner = props[0].getOwnerName();
if(!StringUtil.isEmpty(owner)) owner=ListUtil.last(owner, '.').trim();
String fieldType;
if(!StringUtil.isEmpty(owner)){
String id=owner+"id";
for(int y=0;y<props.length;y++){
fieldType = Caster.toString(props[y].getDynamicAttributes().get(KeyConstants._fieldtype,null),null);
if(StringUtil.isEmpty(fieldType,true) && props[y].getName().equalsIgnoreCase(id)){
ids.add(props[y]);
props[y].getDynamicAttributes().setEL(KeyConstants._fieldtype, "id");
}
}
}
}
return ids.toArray(new Property[ids.size()]);
}
public static Object getPropertyValue(Component cfc, String name, Object defaultValue) {
Property[] props=getProperties(cfc);
for(int i=0;i<props.length;i++){
if(!props[i].getName().equalsIgnoreCase(name)) continue;
return cfc.getComponentScope().get(KeyImpl.getInstance(name),null);
}
return defaultValue;
}
/* jira2049
public static Object getPropertyValue(ORMSession session,Component cfc, String name, Object defaultValue) {
Property[] props=getProperties(cfc);
Object raw=null;
SessionImpl sess=null;
if(session!=null){
raw=session.getRawSession();
if(raw instanceof SessionImpl)
sess=(SessionImpl) raw;
}
Object val;
for(int i=0;i<props.length;i++){
if(!props[i].getName().equalsIgnoreCase(name)) continue;
val = cfc.getComponentScope().get(KeyImpl.getInstance(name),null);
if(sess!=null && !(val instanceof PersistentCollection)){
if(val instanceof List)
return new PersistentList(sess,(List)val);
if(val instanceof Map && !(val instanceof Component))
return new PersistentMap(sess,(Map)val);
if(val instanceof Set)
return new PersistentSet(sess,(Set)val);
if(val instanceof Array)
return new PersistentList(sess,Caster.toList(val,null));
}
return val;
}
return defaultValue;
}*/
private static Property[] getProperties(Component cfc) {
if(cfc instanceof ComponentPro)
return ((ComponentPro)cfc).getProperties(true,true,false,false);
return cfc.getProperties(true);
}
public static boolean isRelated(Property prop) {
String fieldType = Caster.toString(prop.getDynamicAttributes().get(KeyConstants._fieldtype,"column"),"column");
if(StringUtil.isEmpty(fieldType,true)) return false;
fieldType=fieldType.toLowerCase().trim();
if("one-to-one".equals(fieldType)) return true;
if("many-to-one".equals(fieldType)) return true;
if("one-to-many".equals(fieldType)) return true;
if("many-to-many".equals(fieldType)) return true;
return false;
}
public static Struct convertToSimpleMap(String paramsStr) {
paramsStr=paramsStr.trim();
if(!StringUtil.startsWith(paramsStr, '{') || !StringUtil.endsWith(paramsStr, '}'))
return null;
paramsStr = paramsStr.substring(1, paramsStr.length() - 1);
String items[] = ListUtil.listToStringArray(paramsStr, ',');
Struct params=new StructImpl();
String arr$[] = items;
int index;
for(int i = 0; i < arr$.length; i++) {
String pair = arr$[i];
index = pair.indexOf('=');
if(index == -1) return null;
params.setEL(
KeyImpl.init(deleteQuotes(pair.substring(0, index).trim()).trim()),
deleteQuotes(pair.substring(index + 1).trim()));
}
return params;
}
private static String deleteQuotes(String str) {
if(StringUtil.isEmpty(str,true))return "";
char first=str.charAt(0);
if((first=='\'' || first=='"') && StringUtil.endsWith(str, first))
return str.substring(1, str.length() - 1);
return str;
}
public static DataSource getDataSource(PageContext pc) throws PageException{
pc=ThreadLocalPageContext.get(pc);
Object o=((ApplicationContextPro)pc.getApplicationContext()).getORMDataSource();
if(StringUtil.isEmpty(o))
throw ExceptionUtil.createException(ORMUtil.getSession(pc),null,"missing datasource defintion in "+Constants.APP_CFC+"/"+Constants.CFAPP_NAME,null);
return o instanceof DataSource?(DataSource)o:((PageContextImpl)pc).getDataSource(Caster.toString(o));
}
public static DataSource getDataSource(PageContext pc, DataSource defaultValue) {
pc=ThreadLocalPageContext.get(pc);
Object o=((ApplicationContextPro)pc.getApplicationContext()).getORMDataSource();
if(StringUtil.isEmpty(o))
return defaultValue;
try {
return o instanceof DataSource?(DataSource)o:((PageContextImpl)pc).getDataSource(Caster.toString(o));
}
catch (PageException e) {
return defaultValue;
}
}
}