001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.orm.hibernate;
020
021import java.io.BufferedReader;
022import java.io.BufferedWriter;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.InputStreamReader;
026import java.io.OutputStream;
027import java.io.OutputStreamWriter;
028import java.io.Reader;
029import java.io.Serializable;
030import java.io.StringWriter;
031import java.io.Writer;
032import java.lang.reflect.Method;
033import java.nio.charset.Charset;
034import java.sql.ResultSet;
035import java.util.ArrayList;
036import java.util.Iterator;
037import java.util.List;
038
039import javax.xml.parsers.FactoryConfigurationError;
040import javax.xml.parsers.ParserConfigurationException;
041
042import lucee.commons.io.res.Resource;
043import lucee.commons.lang.types.RefBoolean;
044import lucee.loader.engine.CFMLEngineFactory;
045import lucee.loader.util.Util;
046import lucee.runtime.Component;
047import lucee.runtime.MappingImpl;
048import lucee.runtime.PageContext;
049import lucee.runtime.component.Property;
050import lucee.runtime.component.PropertyImpl;
051import lucee.runtime.config.Config;
052import lucee.runtime.config.ConfigWebImpl;
053import lucee.runtime.db.DataSource;
054import lucee.runtime.db.DatasourceConnection;
055import lucee.runtime.db.SQL;
056import lucee.runtime.db.SQLItem;
057import lucee.runtime.db.SQLItemImpl;
058import lucee.runtime.engine.ThreadLocalPageContext;
059import lucee.runtime.exp.PageException;
060import lucee.runtime.op.Caster;
061import lucee.runtime.op.Operator;
062import lucee.runtime.orm.hibernate.tuplizer.proxy.ComponentProProxy;
063import lucee.runtime.text.xml.XMLUtil;
064import lucee.runtime.type.Array;
065import lucee.runtime.type.Collection;
066import lucee.runtime.type.Collection.Key;
067import lucee.runtime.type.Query;
068import lucee.runtime.type.QueryImpl;
069import lucee.runtime.type.Struct;
070import lucee.runtime.type.dt.DateTime;
071import lucee.runtime.type.scope.Argument;
072import lucee.runtime.type.util.ListUtil;
073import lucee.runtime.util.Cast;
074import lucee.runtime.util.Creation;
075import lucee.runtime.util.Decision;
076
077import org.hibernate.JDBCException;
078import org.hibernate.exception.ConstraintViolationException;
079import org.w3c.dom.Document;
080import org.w3c.dom.Node;
081import org.xml.sax.SAXException;
082
083public class CommonUtil {
084        
085        public static final Key ENTITY_NAME = CommonUtil.createKey("entityname");
086        public static final Key FIELDTYPE = CommonUtil.createKey("fieldtype");
087        public static final Key POST_INSERT=CommonUtil.createKey("postInsert");
088        public static final Key POST_UPDATE=CommonUtil.createKey("postUpdate");
089        public static final Key PRE_DELETE=CommonUtil.createKey("preDelete");
090        public static final Key POST_DELETE=CommonUtil.createKey("postDelete");
091        public static final Key PRE_LOAD=CommonUtil.createKey("preLoad");
092        public static final Key POST_LOAD=CommonUtil.createKey("postLoad");
093        public static final Key PRE_UPDATE=CommonUtil.createKey("preUpdate");
094        public static final Key PRE_INSERT=CommonUtil.createKey("preInsert");
095        public static final Key INIT=CommonUtil.createKey("init");
096        private static final short INSPECT_UNDEFINED = (short)4; /*ConfigImpl.INSPECT_UNDEFINED*/
097        
098        private static Charset charset;
099        
100        public static final Charset UTF8;
101        public static final Charset ISO88591;
102        public static final Charset UTF16BE;
103        public static final Charset UTF16LE;
104        
105        static {
106                UTF8=Charset.forName("utf-8");
107                ISO88591=Charset.forName("iso-8859-1");
108                UTF16BE=Charset.forName("utf-16BE");
109                UTF16LE=Charset.forName("UTF-16LE");
110                
111                String strCharset=System.getProperty("file.encoding");
112                if(strCharset==null || strCharset.equalsIgnoreCase("MacRoman"))
113                        strCharset="cp1252";
114
115                if(strCharset.equalsIgnoreCase("utf-8")) charset=UTF8;
116                else charset=Charset.forName(strCharset);
117        }
118        
119
120        
121        private static Cast caster;
122        private static Decision decision;
123        private static Creation creator;
124
125
126        public static Object castTo(PageContext pc, Class trgClass, Object obj) throws PageException {
127                return Caster.castTo(pc, trgClass, obj);
128        }
129        
130        public static Array toArray(Object obj) throws PageException {
131                return caster().toArray(obj);
132        }
133        public static Array toArray(Object obj, Array defaultValue) {
134                return caster().toArray(obj,defaultValue);
135        }
136
137        public static Boolean toBoolean(String str) throws PageException {
138                return caster().toBoolean(str);
139        }
140        public static Boolean toBoolean(String str, Boolean defaultValue) {
141                return caster().toBoolean(str,defaultValue);
142        }
143        public static Boolean toBoolean(Object obj) throws PageException {
144                return caster().toBoolean(obj);
145        }
146        public static Boolean toBoolean(Object obj, Boolean defaultValue) {
147                return caster().toBoolean(obj,defaultValue);
148        }
149
150        public static Boolean toBooleanValue(String str) throws PageException {
151                return caster().toBooleanValue(str);
152        }
153        public static Boolean toBooleanValue(String str, Boolean defaultValue) {
154                return caster().toBooleanValue(str,defaultValue);
155        }
156        public static boolean toBooleanValue(Object obj) throws PageException {
157                return caster().toBooleanValue(obj);
158        }
159        public static boolean toBooleanValue(Object obj, boolean defaultValue) {
160                return caster().toBooleanValue(obj,defaultValue);
161        }
162
163        public static Component toComponent(Object obj) throws PageException {
164                return Caster.toComponent(obj);
165        }
166        public static Component toComponent(Object obj, Component defaultValue) {
167                return Caster.toComponent(obj,defaultValue);
168        }
169
170        public static Object toList(String[] arr, String delimiter) { 
171                return ListUtil.arrayToList(arr, delimiter);
172        }
173        
174        public static String toString(Object obj, String defaultValue) {
175                return caster().toString(obj,defaultValue);
176        }
177        public static String toString(Object obj) throws PageException {
178                return caster().toString(obj);
179        }
180        public static String toString(boolean b) {
181                return caster().toString(b);
182        }
183        public static String toString(double d) {
184                return caster().toString(d);
185        }
186        public static String toString(int i) {
187                return caster().toString(i);
188        }
189        public static String toString(long l) {
190                return caster().toString(l);
191        }
192
193        /**
194            * reads String data from File
195             * @param file 
196             * @param charset 
197             * @return readed string
198            * @throws IOException
199            */
200           public static String toString(Resource file, Charset charset) throws IOException {
201               Reader r = null;
202               try {
203                   r = getReader(file,charset);
204                   String str = toString(r);
205                   return str;
206               }
207               finally {
208                   closeEL(r);
209               }
210           }
211        
212           public static String toString(Reader reader) throws IOException {
213               StringWriter sw=new StringWriter(512);
214               copy(toBufferedReader(reader),sw);
215               sw.close();
216               return sw.toString();
217           }
218           
219           public static BufferedReader toBufferedReader(Reader r) {
220                        if(r instanceof BufferedReader) return (BufferedReader) r;
221                        return new BufferedReader(r);
222                }
223           
224           private static final void copy(Reader r, Writer w) throws IOException {
225                copy(r,w,0xffff);
226            }
227           
228           private static final void copy(Reader r, Writer w, int blockSize) throws IOException {
229                char[] buffer = new char[blockSize];
230                int len;
231
232                while((len = r.read(buffer)) !=-1)
233                  w.write(buffer, 0, len);
234            }
235        
236        public static Reader getReader(Resource res, Charset charset) throws IOException {
237                InputStream is=null;
238                try {
239                        is = res.getInputStream();
240                        boolean markSupported=is.markSupported();
241                if(markSupported) is.mark(4);
242                int first = is.read();
243                int second = is.read();
244                // FE FF        UTF-16, big-endian
245                if (first == 0xFE && second == 0xFF)    {
246                        return _getReader(is, UTF16BE);
247                }
248                // FF FE        UTF-16, little-endian
249                if (first == 0xFF && second == 0xFE)    {
250                        return _getReader(is, UTF16LE);
251                }
252                
253                int third=is.read();
254                // EF BB BF     UTF-8
255                if (first == 0xEF && second == 0xBB && third == 0xBF)    {
256                        //is.reset();
257                                return _getReader(is,UTF8);
258                }
259
260                if(markSupported) {
261                        is.reset();
262                        return _getReader(is,charset);
263                }
264                }
265                catch(IOException ioe) {
266                        closeEL(is);
267                        throw ioe;
268                }
269                
270        // when mark not supported return new reader
271        closeEL(is);
272        is=null;
273                try {
274                        is=res.getInputStream();
275                }
276                catch(IOException ioe) {
277                        closeEL(is);
278                        throw ioe;
279                }
280        return _getReader(is, charset);             
281   }
282        
283        private static Reader _getReader(InputStream is, Charset cs)  {
284                 if(cs==null) cs=charset;
285             return new BufferedReader(new InputStreamReader(is,cs));
286         }
287
288        public static String[] toStringArray(String list, char delimiter) { 
289                return ListUtil.listToStringArray(list, delimiter);
290        }
291        public static String[] toStringArray(String list, String delimiter) { 
292                return ListUtil.toStringArray(ListUtil.listToArray(list,delimiter),""); //TODO better
293        }
294        
295        public static Integer toInteger(Object obj) throws PageException {
296                return caster().toInteger(obj);
297        }
298        public static Integer toInteger(Object obj, Integer defaultValue) {
299                return caster().toInteger(obj, defaultValue);
300        }
301        public static int toIntValue(Object obj) throws PageException {
302                return caster().toIntValue(obj);
303        }
304        public static int toIntValue(Object obj, int defaultValue) {
305                return caster().toIntValue(obj,defaultValue);
306        }
307        
308        public static Array toArray(Argument arg) {
309                Array trg=createArray();
310                int[] keys = arg.intKeys();
311                for(int i=0;i<keys.length;i++){
312                        trg.setEL(keys[i],
313                                        arg.get(keys[i],null));
314                }
315                return trg;
316        }
317        
318        public static PageException toPageException(Throwable t) {
319                lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
320                PageException pe = caster().toPageException(t);;
321                if (t instanceof org.hibernate.HibernateException) {
322                        org.hibernate.HibernateException he = (org.hibernate.HibernateException)t;
323                        Throwable cause = he.getCause();
324                        if(cause != null) {
325                                pe = caster().toPageException( cause );
326                                ExceptionUtil.setAdditional(pe, CommonUtil.createKey("hibernate exception"), t );
327                        }
328                }
329                if ( t instanceof JDBCException ) {
330                        JDBCException je = (JDBCException)t;
331                        ExceptionUtil.setAdditional(pe, CommonUtil.createKey("sql"), je.getSQL());
332                }
333                if( t instanceof ConstraintViolationException) {
334                        ConstraintViolationException cve = (ConstraintViolationException)t;
335                        if(!Util.isEmpty(cve.getConstraintName())) {
336                                ExceptionUtil.setAdditional(pe, CommonUtil.createKey("constraint name"), cve.getConstraintName());
337                        }
338                }
339                return pe;
340                
341        }
342        public static Serializable toSerializable(Object obj) throws PageException {
343                return caster().toSerializable(obj);
344        }
345        public static Serializable toSerializable(Object obj,Serializable defaultValue) {
346                return caster().toSerializable(obj,defaultValue);
347        }
348
349        public static Struct toStruct(Object obj) throws PageException {
350                return caster().toStruct(obj);
351        }
352        public static Struct toStruct(Object obj, Struct defaultValue) {
353                return caster().toStruct(obj,defaultValue);
354        }
355
356        public static SQLItem toSQLItem(Object value, int type) {
357                return new SQLItemImpl(value,type);
358        }
359        
360        public static Object[] toNativeArray(Object obj) throws PageException {
361                return Caster.toNativeArray(obj);
362        }
363        
364        public static String toTypeName(Object obj) {
365                return caster().toTypeName(obj);
366        }
367        public static Node toXML(Object obj) throws PageException {
368                return caster().toXML(obj);
369        }
370        public static Node toXML(Object obj, Node defaultValue) {
371                return caster().toXML(obj,defaultValue);
372        }
373        
374
375        public static Document toDocument(Resource res, Charset cs) throws IOException, SAXException {
376                return XMLUtil.parse(XMLUtil.toInputSource(res,cs), null, false);
377        }
378        
379        
380        
381
382        public static boolean isArray(Object obj) {
383                return decision().isArray(obj);
384        }
385        
386        public static boolean isStruct(Object obj) {
387                return decision().isStruct(obj);
388        }
389        
390        public static Array createArray(){
391                return creator().createArray();
392        }
393
394        public static DateTime createDateTime(long time) {
395                return creator().createDateTime(time);
396        }
397
398        public static Property createProperty(String name, String type) {
399                PropertyImpl pi = new PropertyImpl();
400                pi.setName(name);
401                pi.setType(type);
402                return pi;
403        }
404        
405        public static Struct createStruct(){
406                return creator().createStruct();
407        }
408        public static Collection.Key createKey(String key){
409                return creator().createKey(key);
410        }
411        public static Query createQuery(Collection.Key[] columns, int rows, String name) throws PageException{
412                return creator().createQuery(columns, rows, name);
413        }
414        public static Query createQuery(Array names, Array types, int rows, String name) throws PageException{ 
415                return new QueryImpl(names,types,rows,name);
416        }
417
418        public static RefBoolean createRefBoolean() {
419                return new RefBooleanImpl();
420        }
421        
422        public static Key[] keys(Collection coll) { 
423                if(coll==null) return new Key[0];
424                Iterator<Key> it = coll.keyIterator();
425                List<Key> rtn=new ArrayList<Key>();
426                if(it!=null)while(it.hasNext()){
427                        rtn.add(it.next());
428                }
429                return rtn.toArray(new Key[rtn.size()]);
430        }
431        
432        
433        
434        private static Creation creator() {
435                if(creator==null)
436                        creator=CFMLEngineFactory.getInstance().getCreationUtil();
437                return creator;
438        }
439
440        private static Decision decision() {
441                if(decision==null)
442                        decision=CFMLEngineFactory.getInstance().getDecisionUtil();
443                return decision;
444        }
445        private static Cast caster() {
446                if(caster==null)
447                        caster=CFMLEngineFactory.getInstance().getCastUtil();
448                return caster;
449        }
450        
451
452        /**
453         * represents a SQL Statement with his defined arguments for a prepared statement
454         */
455        static class SQLImpl implements SQL {
456            
457            private String strSQL;
458            
459            /**
460             * Constructor only with SQL String
461             * @param strSQL SQL String
462             */
463            public SQLImpl(String strSQL) {
464                this.strSQL=strSQL;
465            }
466            
467            
468            public void addItems(SQLItem item) {
469                
470            }
471            
472            @Override
473            public SQLItem[] getItems() {
474                return new SQLItem[0];
475            }
476
477            @Override
478            public int getPosition() {
479                return 0;
480            }
481            
482            @Override
483            public void setPosition(int position) {
484            }    
485            
486
487            @Override
488            public String getSQLString() {
489                return strSQL;
490            }
491            
492            @Override
493            public void setSQLString(String strSQL) {
494                this.strSQL= strSQL;
495            }
496
497            @Override
498            public String toString() {
499                return strSQL;
500            }    
501            
502            @Override
503            public String toHashString() {
504                return strSQL;
505            }
506        }
507        
508        /**
509         * Integer Type that can be modified
510         */
511        public static final class RefBooleanImpl implements RefBoolean {//MUST add interface Castable
512
513            private boolean value;
514
515
516            public RefBooleanImpl() {}
517            
518            /**
519             * @param value
520             */
521            public RefBooleanImpl(boolean value) {
522                this.value=value;
523            }
524            
525            /**
526             * @param value
527             */
528            public void setValue(boolean value) {
529                this.value = value;
530            }
531            
532            /**
533             * @return returns value as Boolean Object
534             */
535            public Boolean toBoolean() {
536                return value?Boolean.TRUE:Boolean.FALSE;
537            }
538            
539            /**
540             * @return returns value as boolean value
541             */
542            public boolean toBooleanValue() {
543                return value;
544            }
545            
546            @Override
547            public String toString() {
548                return value?"true":"false";
549            }
550        }
551
552        public static DataSource getDataSource(PageContext pc, String name) throws PageException {
553                try{
554                        Method m = pc.getClass().getMethod("getDataSource", new Class[]{String.class});
555                        return (DataSource) m.invoke(pc, new Object[]{name});
556                }
557                catch (Throwable t) {
558                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
559                        throw caster().toPageException(t);
560                }
561        }
562
563        public static DatasourceConnection getDatasourceConnection(PageContext pc, DataSource ds) throws PageException {
564                return ((ConfigWebImpl)pc.getConfig()).getDatasourceConnectionPool().getDatasourceConnection(ds,null,null); // TODO use reflection
565        }
566        
567        public static void releaseDatasourceConnection(PageContext pc, DatasourceConnection dc) {
568                ((ConfigWebImpl)pc.getConfig()).getDatasourceConnectionPool().releaseDatasourceConnection(pc.getConfig(),dc,true); // TODO use reflection
569        }
570
571        public static MappingImpl createMapping(Config config, String virtual, String physical) {
572                return new MappingImpl(config,
573                                virtual,
574                                physical,
575                                null,INSPECT_UNDEFINED,true,false,false,false,true,true,null
576                                );
577        }
578        
579        public static String last(String list, char delimiter) {
580                return ListUtil.last(list, delimiter);
581        }
582        
583        public static String last(String list, String delimiter) {
584                return ListUtil.last(list, delimiter,true);
585        }
586        
587        public static int listFindNoCaseIgnoreEmpty(String list, String value, char delimiter) {
588                return ListUtil.listFindNoCaseIgnoreEmpty(list,value,delimiter);
589        }
590        
591        public static String[] trimItems(String[] arr) {
592                for(int i=0;i<arr.length;i++) {
593                        arr[i]=arr[i].trim();
594                }
595                return arr;
596        }
597        
598        public static Document getDocument(Node node) {
599                return XMLUtil.getDocument(node);
600        }
601        public static Document newDocument() throws ParserConfigurationException, FactoryConfigurationError {
602                return XMLUtil.newDocument();
603        }
604        public static void setFirst(Node parent, Node node) {
605                XMLUtil.setFirst(parent, node);
606        }
607
608        public static Property[] getProperties(Component c,boolean onlyPeristent, boolean includeBaseProperties, boolean preferBaseProperties, boolean inheritedMappedSuperClassOnly) {
609                return ComponentProProxy.getProperties(c, onlyPeristent, includeBaseProperties, preferBaseProperties, inheritedMappedSuperClassOnly);
610        }
611
612        public static void write(Resource res, String string, Charset cs, boolean append) throws IOException {
613                if(cs==null) cs=charset;
614
615                Writer writer=null;
616                try {
617                        writer=getWriter(res, cs,append);
618                        writer.write(string);
619                }
620                finally {
621                        closeEL(writer);
622                }
623        }
624        
625        public static Writer getWriter(Resource res, Charset charset, boolean append) throws IOException {
626                OutputStream os=null;
627                try {
628                        os=res.getOutputStream(append);
629                }
630                catch(IOException ioe) {
631                        closeEL(os);
632                        throw ioe;
633                }
634                return getWriter(os, charset);
635        }
636        
637        public static Writer getWriter(OutputStream os, Charset cs) {
638                if(cs==null) cs=charset;
639                return new BufferedWriter(new OutputStreamWriter(os,charset));
640        }
641
642        public static BufferedReader toBufferedReader(Resource res, Charset charset) throws IOException {
643                return toBufferedReader(getReader(res,(Charset)null));
644        }
645        
646        public static boolean equalsComplexEL(Object left, Object right) {
647                return Operator.equalsComplexEL(left, right, false,true);
648        }
649
650        public static void setEntity(Component c, boolean entity) { 
651                ComponentProProxy.setEntity(c,entity);
652        }
653
654        public static PageContext pc() {
655                //return CFMLEngineFactory.getInstance().getThreadPageContext();
656                return ThreadLocalPageContext.get();
657        }
658
659        public static Config config() { 
660                //return CFMLEngineFactory.getInstance().getThreadPageContext().getConfig();
661                return ThreadLocalPageContext.getConfig();
662        }
663
664        public static boolean isPersistent(Component c) {
665                return ComponentProProxy.isPersistent(c);
666        }
667
668        public static Object getMetaStructItem(Component c, Key name) {
669                return ComponentProProxy.getMetaStructItem(c,name);
670        }
671        
672        public static void closeEL(OutputStream os) {
673                if(os!=null) {
674                        try {
675                                os.close();
676                        }
677                        catch (Throwable t) {
678                                lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
679                        }
680                }
681        }
682        
683        public static void closeEL(Writer w) {
684                if(w!=null) {
685                        try {
686                                w.close();
687                        }
688                        catch (Throwable t) {
689                                lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
690                        }
691                }
692        }
693
694        public static void closeEL(ResultSet rs) {
695                if(rs!=null) {
696                        try {
697                                rs.close();
698                        }
699                        catch (Throwable t) {
700                                lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
701                        }
702                }
703        }
704        
705        public static void closeEL(InputStream is) {
706         try {
707                 if(is!=null)is.close();
708         } 
709         catch (Throwable t) {
710                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
711        }
712    }
713        
714        public static void closeEL(Reader r) {
715         try {
716                 if(r!=null)r.close();
717         } 
718         catch (Throwable t) {
719                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
720        }
721    }
722}