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.loader.engine; 020 021import java.io.BufferedOutputStream; 022import java.io.ByteArrayInputStream; 023import java.io.EOFException; 024import java.io.File; 025import java.io.FileInputStream; 026import java.io.FileOutputStream; 027import java.io.IOException; 028import java.io.InputStream; 029import java.io.OutputStream; 030import java.io.PrintWriter; 031import java.io.UnsupportedEncodingException; 032import java.lang.reflect.InvocationTargetException; 033import java.lang.reflect.Method; 034import java.net.URL; 035import java.net.URLDecoder; 036import java.util.ArrayList; 037import java.util.Arrays; 038import java.util.Date; 039import java.util.Iterator; 040import java.util.List; 041 042import javax.servlet.ServletConfig; 043import javax.servlet.ServletException; 044 045import lucee.Version; 046import lucee.loader.TP; 047import lucee.loader.classloader.LuceeClassLoader; 048import lucee.loader.util.ExtensionFilter; 049import lucee.loader.util.Util; 050import lucee.loader.util.ZipUtil; 051 052import com.intergral.fusiondebug.server.FDControllerFactory; 053 054/** 055 * Factory to load CFML Engine 056 */ 057public class CFMLEngineFactory { 058 059 // set to false to disable patch loading, for example in major alpha releases 060 private static final boolean PATCH_ENABLED = true; 061 062 private static CFMLEngineFactory factory; 063 private static CFMLEngineWrapper engineListener; 064 private CFMLEngine engine; 065 private ClassLoader mainClassLoader=new TP().getClass().getClassLoader(); 066 private int version; 067 private List<EngineChangeListener> listeners=new ArrayList<EngineChangeListener>(); 068 069 070 private static File luceeServerRoot; 071 private File resourceRoot; 072 073 private PrintWriter out; 074 075 076 /** 077 * Constructor of the class 078 */ 079 protected CFMLEngineFactory(){ 080 } 081 082 /** 083 * returns instance of this factory (singelton-> always the same instance) 084 * do auto update when changes occur 085 * @param config 086 * @return Singelton Instance of the Factory 087 * @throws ServletException 088 */ 089 public static CFMLEngine getInstance(ServletConfig config) throws ServletException { 090 091 if(engineListener!=null) { 092 if(factory==null) factory=engineListener.getCFMLEngineFactory(); 093 return engineListener; 094 } 095 096 if(factory==null) factory=new CFMLEngineFactory(); 097 098 099 // read init param from config 100 factory.setInitParam(config); 101 102 CFMLEngine engine = factory.getEngine(); 103 engine.addServletConfig(config); 104 engineListener = new CFMLEngineWrapper(engine); 105 106 // add listener for update 107 factory.addListener(engineListener); 108 return engineListener; 109 } 110 111 /** 112 * returns instance of this factory (singelton-> always the same instance) 113 * do auto update when changes occur 114 * @return Singelton Instance of the Factory 115 * @throws RuntimeException 116 */ 117 public static CFMLEngine getInstance() throws RuntimeException { 118 if(engineListener!=null) return engineListener; 119 throw new RuntimeException("engine is not initalized, you must first call getInstance(ServletConfig)"); 120 } 121 122 /** 123 * used only for internal usage 124 * @param engine 125 * @throws RuntimeException 126 */ 127 public static void registerInstance(CFMLEngine engine) throws RuntimeException { 128 if(factory==null) factory=engine.getCFMLEngineFactory(); 129 130 // first update existing listener 131 if(engineListener!=null) { 132 if(engineListener.equalTo(engine, true)) return; 133 engineListener.onUpdate(engine);// perhaps this is still refrenced in the code, because of that we update it 134 factory.removeListener(engineListener); 135 } 136 137 // now register this 138 if(engine instanceof CFMLEngineWrapper) 139 engineListener=(CFMLEngineWrapper) engine; 140 else 141 engineListener = new CFMLEngineWrapper(engine); 142 143 factory.addListener(engineListener); 144 } 145 146 147 /** 148 * returns instance of this factory (singelton-> always the same instance) 149 * @param config 150 * @param listener 151 * @return Singelton Instance of the Factory 152 * @throws ServletException 153 */ 154 public static CFMLEngine getInstance(ServletConfig config, EngineChangeListener listener) throws ServletException { 155 getInstance(config); 156 157 // add listener for update 158 factory.addListener(listener); 159 160 // read init param from config 161 factory.setInitParam(config); 162 163 CFMLEngine e = factory.getEngine(); 164 e.addServletConfig(config); 165 166 // make the FDController visible for the FDClient 167 FDControllerFactory.makeVisible(); 168 169 return e; 170 } 171 172 void setInitParam(ServletConfig config) { 173 if(luceeServerRoot!=null) return; 174 175 String initParam=config.getInitParameter("lucee-server-directory"); 176 if(Util.isEmpty(initParam))initParam=config.getInitParameter("lucee-server-root"); 177 if(Util.isEmpty(initParam))initParam=config.getInitParameter("lucee-server-dir"); 178 if(Util.isEmpty(initParam))initParam=config.getInitParameter("lucee-server"); 179 180 if(Util.isEmpty(initParam))initParam=config.getInitParameter("railo-server-directory"); 181 if(Util.isEmpty(initParam))initParam=config.getInitParameter("railo-server-root"); 182 if(Util.isEmpty(initParam))initParam=config.getInitParameter("railo-server-dir"); 183 if(Util.isEmpty(initParam))initParam=config.getInitParameter("railo-server"); 184 185 186 187 188 initParam=Util.parsePlaceHolder(Util.removeQuotes(initParam,true)); 189 190 try { 191 if(!Util.isEmpty(initParam)) { 192 File root=new File(initParam); 193 if(!root.exists()) { 194 if(root.mkdirs()) { 195 luceeServerRoot=root.getCanonicalFile(); 196 return; 197 } 198 } 199 else if(root.canWrite()) { 200 luceeServerRoot=root.getCanonicalFile(); 201 return; 202 } 203 } 204 } 205 catch(IOException ioe){} 206 } 207 208 209 /** 210 * adds a listener to the factory that will be informed when a new engine will be loaded. 211 * @param listener 212 */ 213 private void addListener(EngineChangeListener listener) { 214 if(!listeners.contains(listener)) { 215 listeners.add(listener); 216 } 217 } 218 219 private void removeListener(EngineChangeListener listener) { 220 listeners.remove(listener); 221 } 222 223 /** 224 * @return CFML Engine 225 * @throws ServletException 226 */ 227 private CFMLEngine getEngine() throws ServletException { 228 if(engine==null)initEngine(); 229 return engine; 230 } 231 232 private void initEngine() throws ServletException { 233 234 int coreVersion=Version.getIntVersion(); 235 long coreCreated=Version.getCreateTime(); 236 237 238 // get newest lucee version as file 239 File patcheDir=null; 240 try { 241 patcheDir = getPatchDirectory(); 242 log("lucee-server-root:"+patcheDir.getParent()); 243 } 244 catch (IOException e) { 245 throw new ServletException(e); 246 } 247 248 File[] patches=PATCH_ENABLED?patcheDir.listFiles(new ExtensionFilter(new String[]{"."+getCoreExtension()})):null; 249 File lucee=null; 250 if(patches!=null) { 251 for(int i=0;i<patches.length;i++) { 252 if(patches[i].getName().startsWith("tmp.lco")) { 253 patches[i].delete(); 254 } 255 else if(patches[i].lastModified()<coreCreated) { 256 patches[i].delete(); 257 } 258 else if(lucee==null || isNewerThan(Util.toInVersion(patches[i].getName()),Util.toInVersion(lucee.getName()))) { 259 lucee=patches[i]; 260 } 261 } 262 } 263 264 265 if(lucee!=null && isNewerThan(coreVersion,Util.toInVersion(lucee.getName())))lucee=null; 266 267 // Load Lucee 268 //URL url=null; 269 try { 270 // Load core version when no patch available 271 if(lucee==null) { 272 tlog("Load Build in Core"); 273 // 274 String coreExt=getCoreExtension(); 275 engine=getCore(coreExt); 276 277 278 lucee=new File(patcheDir,engine.getVersion()+"."+coreExt); 279 if(PATCH_ENABLED) { 280 InputStream bis = new TP().getClass().getResourceAsStream("/core/core."+coreExt); 281 OutputStream bos=new BufferedOutputStream(new FileOutputStream(lucee)); 282 Util.copy(bis,bos); 283 Util.closeEL(bis,bos); 284 } 285 } 286 else { 287 try { 288 engine=getEngine(new LuceeClassLoader(lucee,mainClassLoader)); 289 } 290 catch(EOFException e) { 291 System.err.println("Lucee patch file "+lucee+" is invalid, please delete it"); 292 engine=getCore(getCoreExtension()); 293 } 294 } 295 version=Util.toInVersion(engine.getVersion()); 296 297 tlog("Loaded Lucee Version "+engine.getVersion()); 298 } 299 catch(InvocationTargetException e) { 300 e.getTargetException().printStackTrace(); 301 throw new ServletException(e.getTargetException()); 302 } 303 catch(Exception e) { 304 e.printStackTrace(); 305 throw new ServletException(e); 306 } 307 308 //check updates 309 String updateType=engine.getUpdateType(); 310 if(updateType==null || updateType.length()==0)updateType="manuell"; 311 312 if(updateType.equalsIgnoreCase("auto")) { 313 new UpdateChecker(this).start(); 314 } 315 316 } 317 318 319 private String getCoreExtension() { 320 return "lco"; 321 } 322 323 private CFMLEngine getCore(String ext) throws SecurityException, IllegalArgumentException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, IOException { 324 InputStream is = null; 325 try { 326 is = new TP().getClass().getResourceAsStream("/core/core."+ext); 327 LuceeClassLoader classLoader=new LuceeClassLoader(is,mainClassLoader,ext.equalsIgnoreCase("rcs")); 328 return getEngine(classLoader); 329 } 330 finally { 331 Util.closeEL(is); 332 } 333 } 334 335 /** 336 * method to initalize a update of the CFML Engine. 337 * checks if there is a new Version and update it whwn a new version is available 338 * @param password 339 * @return has updated 340 * @throws IOException 341 * @throws ServletException 342 */ 343 public boolean update(String password) throws IOException, ServletException { 344 if(!engine.can(CFMLEngine.CAN_UPDATE,password)) 345 throw new IOException("access denied to update CFMLEngine"); 346 //new RunUpdate(this).start(); 347 return update(); 348 } 349 350 /** 351 * restart the cfml engine 352 * @param password 353 * @return has updated 354 * @throws IOException 355 * @throws ServletException 356 */ 357 public boolean restart(String password) throws IOException, ServletException { 358 if(!engine.can(CFMLEngine.CAN_RESTART_ALL,password)) 359 throw new IOException("access denied to restart CFMLEngine"); 360 361 return _restart(); 362 } 363 364 /** 365 * restart the cfml engine 366 * @param password 367 * @return has updated 368 * @throws IOException 369 * @throws ServletException 370 */ 371 public boolean restart(String configId, String password) throws IOException, ServletException { 372 if(!engine.can(CFMLEngine.CAN_RESTART_CONTEXT,password))// TODO restart single context 373 throw new IOException("access denied to restart CFML Context (configId:"+configId+")"); 374 375 return _restart(); 376 } 377 378 /** 379 * restart the cfml engine 380 * @param password 381 * @return has updated 382 * @throws IOException 383 * @throws ServletException 384 */ 385 private synchronized boolean _restart() throws ServletException { 386 engine.reset(); 387 initEngine(); 388 registerInstance(engine); 389 callListeners(engine); 390 System.gc(); 391 System.gc(); 392 return true; 393 } 394 395 /** 396 * updates the engine when a update is available 397 * @return has updated 398 * @throws IOException 399 * @throws ServletException 400 */ 401 private boolean update() throws IOException, ServletException { 402 403 URL hostUrl=getEngine().getUpdateLocation(); 404 if(hostUrl==null)hostUrl=new URL("http://stable.lucee.org"); 405 URL infoUrl=new URL(hostUrl,"/lucee/remote/version/info.cfm?ext="+getCoreExtension()+"&version="+version);// FUTURE replace with Info.cfc or better move the functionality to core if possible. something like engine.getUpdater a class provided by the core and defined (interface) by the loader. 406 407 tlog("Check for update at "+hostUrl); 408 409 String availableVersion = Util.toString((InputStream)infoUrl.getContent()).trim(); 410 411 if(availableVersion.length()!=9) throw new IOException("can't get update info from ["+infoUrl+"]"); 412 if(!isNewerThan(Util.toInVersion(availableVersion),version)) { 413 tlog("There is no newer Version available"); 414 return false; 415 } 416 417 tlog("Found a newer Version \n - current Version "+Util.toStringVersion(version)+"\n - available Version "+availableVersion); 418 419 URL updateUrl=new URL(hostUrl,"/lucee/remote/version/update.cfm?ext="+getCoreExtension()+"&version="+availableVersion); 420 File patchDir=getPatchDirectory(); 421 File newLucee=new File(patchDir,availableVersion+("."+getCoreExtension())); 422 423 if(newLucee.createNewFile()) { 424 Util.copy((InputStream)updateUrl.getContent(),new FileOutputStream(newLucee)); 425 } 426 else { 427 tlog("File for new Version already exists, won't copy new one"); 428 return false; 429 } 430 try { 431 engine.reset(); 432 } 433 catch(Throwable t) { 434 if(t instanceof ThreadDeath) throw (ThreadDeath)t; 435 t.printStackTrace(); 436 } 437 438 // Test new lucee version valid 439 //FileClassLoader classLoader=new FileClassLoader(newLucee,mainClassLoader); 440 LuceeClassLoader classLoader=new LuceeClassLoader(newLucee,mainClassLoader); 441 //URLClassLoader classLoader=new URLClassLoader(new URL[]{newLucee.toURL()},mainClassLoader); 442 String v=""; 443 try { 444 CFMLEngine e = getEngine(classLoader); 445 if(e==null)throw new IOException("can't load engine"); 446 v=e.getVersion(); 447 engine=e; 448 version=Util.toInVersion(v); 449 //e.reset(); 450 callListeners(e); 451 } 452 catch (Exception e) { 453 classLoader=null; 454 System.gc(); 455 try { 456 newLucee.delete(); 457 } 458 catch(Exception ee){} 459 tlog("There was a Problem with the new Version, can't install ("+e+":"+e.getMessage()+")"); 460 e.printStackTrace(); 461 return false; 462 } 463 464 tlog("Version ("+v+")installed"); 465 return true; 466 } 467 468 469 /** 470 * method to initalize a update of the CFML Engine. 471 * checks if there is a new Version and update it whwn a new version is available 472 * @param password 473 * @return has updated 474 * @throws IOException 475 * @throws ServletException 476 */ 477 public boolean removeUpdate(String password) throws IOException, ServletException { 478 if(!engine.can(CFMLEngine.CAN_UPDATE,password)) 479 throw new IOException("access denied to update CFMLEngine"); 480 return removeUpdate(); 481 } 482 483 484 /** 485 * method to initalize a update of the CFML Engine. 486 * checks if there is a new Version and update it whwn a new version is available 487 * @param password 488 * @return has updated 489 * @throws IOException 490 * @throws ServletException 491 */ 492 public boolean removeLatestUpdate(String password) throws IOException, ServletException { 493 if(!engine.can(CFMLEngine.CAN_UPDATE,password)) 494 throw new IOException("access denied to update CFMLEngine"); 495 return removeLatestUpdate(); 496 } 497 498 499 500 /** 501 * updates the engine when a update is available 502 * @return has updated 503 * @throws IOException 504 * @throws ServletException 505 */ 506 private boolean removeUpdate() throws IOException, ServletException { 507 File patchDir=getPatchDirectory(); 508 File[] patches=patchDir.listFiles(new ExtensionFilter(new String[]{getCoreExtension()})); 509 510 for(int i=0;i<patches.length;i++) { 511 if(!patches[i].delete())patches[i].deleteOnExit(); 512 } 513 _restart(); 514 return true; 515 } 516 517 518 private boolean removeLatestUpdate() throws IOException, ServletException { 519 File patchDir=getPatchDirectory(); 520 File[] patches=patchDir.listFiles(new ExtensionFilter(new String[]{"."+getCoreExtension()})); 521 File patch=null; 522 for(int i=0;i<patches.length;i++) { 523 if(patch==null || isNewerThan(Util.toInVersion(patches[i].getName()),Util.toInVersion(patch.getName()))) { 524 patch=patches[i]; 525 } 526 } 527 if(patch!=null && !patch.delete())patch.deleteOnExit(); 528 529 _restart(); 530 return true; 531 } 532 533 534 public String[] getInstalledPatches() throws ServletException, IOException { 535 File patchDir=getPatchDirectory(); 536 File[] patches=patchDir.listFiles(new ExtensionFilter(new String[]{"."+getCoreExtension()})); 537 538 List<String> list=new ArrayList<String>(); 539 String name; 540 int extLen=getCoreExtension().length()+1; 541 for(int i=0;i<patches.length;i++) { 542 name=patches[i].getName(); 543 name=name.substring(0, name.length()-extLen); 544 list.add(name); 545 } 546 String[] arr = list.toArray(new String[list.size()]); 547 Arrays.sort(arr); 548 return arr; 549 } 550 551 552 /** 553 * call all registred listener for update of the engine 554 * @param engine 555 */ 556 private void callListeners(CFMLEngine engine) { 557 Iterator<EngineChangeListener> it = listeners.iterator(); 558 while(it.hasNext()) { 559 it.next().onUpdate(engine); 560 } 561 } 562 563 564 private File getPatchDirectory() throws IOException { 565 File pd = new File(getResourceRoot(),"patches"); 566 if(!pd.exists())pd.mkdirs(); 567 return pd; 568 } 569 570 /** 571 * return directory to lucee resource root 572 * @return lucee root directory 573 * @throws IOException 574 */ 575 public File getResourceRoot() throws IOException { 576 if(resourceRoot==null) { 577 File parent = getRuningContextRoot(); 578 579 resourceRoot = new File(parent,"lucee-server"); 580 581 // no lucee context 582 if(!resourceRoot.exists()) { 583 // check if there is a Railo context 584 File railoRoot = new File(parent,"railo-server"); 585 if(railoRoot.exists()) { 586 copyRecursiveAndRename(railoRoot,resourceRoot); 587 // zip the railo-server di and delete it (optional) 588 try { 589 File p=railoRoot.getParentFile().getParentFile(); 590 if("lib".equalsIgnoreCase(p.getName()) || "libs".equalsIgnoreCase(p.getName())) 591 p=p.getParentFile(); 592 593 ZipUtil.zip(railoRoot, new File(p,"railo-server-context-old.zip")); 594 Util.delete(railoRoot); 595 } 596 catch(Throwable t){ 597 if(t instanceof ThreadDeath) throw (ThreadDeath)t; 598 t.printStackTrace(); 599 } 600 } 601 else { 602 resourceRoot.mkdirs(); 603 } 604 } 605 } 606 return resourceRoot; 607 } 608 609 private static void copyRecursiveAndRename(File src,File trg) throws IOException { 610 if(!src.exists()) return ; 611 if(src.isDirectory()) { 612 if(!trg.exists())trg.mkdirs(); 613 614 File[] files = src.listFiles(); 615 for(int i=0;i<files.length;i++) { 616 copyRecursiveAndRename(files[i],new File(trg,files[i].getName())); 617 } 618 } 619 else if(src.isFile()) { 620 if(trg.getName().endsWith(".rc") || trg.getName().startsWith(".")) { 621 return; 622 } 623 624 if(trg.getName().equals("railo-server.xml")) { 625 trg=new File(trg.getParentFile(),"lucee-server.xml"); 626 // cfLuceeConfiguration 627 FileInputStream is = new FileInputStream(src); 628 FileOutputStream os = new FileOutputStream(trg); 629 try{ 630 String str=Util.toString(is); 631 str=str.replace("<cfRailoConfiguration", "<!-- copy from Railo context --><cfLuceeConfiguration"); 632 str=str.replace("</cfRailoConfiguration", "</cfLuceeConfiguration"); 633 634 str=str.replace("<railo-configuration", "<!-- copy from Railo context --><cfLuceeConfiguration"); 635 str=str.replace("</railo-configuration", "</cfLuceeConfiguration"); 636 637 638 str=str.replace("{railo-config}", "{lucee-config}"); 639 str=str.replace("{railo-server}", "{lucee-server}"); 640 str=str.replace("{railo-web}", "{lucee-web}"); 641 str=str.replace("\"railo.commons.", "\"lucee.commons."); 642 str=str.replace("\"railo.runtime.", "\"lucee.runtime."); 643 str=str.replace("\"railo.cfx.", "\"lucee.cfx."); 644 str=str.replace("/railo-context.ra", "/lucee-context.lar"); 645 str=str.replace("/railo-context", "/lucee"); 646 str=str.replace("railo-server-context", "lucee-server"); 647 str=str.replace("http://www.getrailo.org", "http://stable.lucee.org"); 648 str=str.replace("http://www.getrailo.com", "http://stable.lucee.org"); 649 650 651 ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes()); 652 653 try { 654 Util.copy(bais, os); 655 bais.close(); 656 } 657 finally { 658 Util.closeEL(is, os); 659 } 660 } 661 finally { 662 Util.closeEL(is,os); 663 } 664 return; 665 } 666 667 FileInputStream is = new FileInputStream(src); 668 FileOutputStream os = new FileOutputStream(trg); 669 try{ 670 Util.copy(is, os); 671 } 672 finally { 673 Util.closeEL(is, os); 674 } 675 } 676 } 677 678 679 /** 680 * @return return running context root 681 * @throws IOException 682 * @throws IOException 683 */ 684 private File getRuningContextRoot() throws IOException { 685 686 if(luceeServerRoot!=null) { 687 return luceeServerRoot; 688 } 689 File dir=getClassLoaderRoot(mainClassLoader); 690 dir.mkdirs(); 691 if(dir.exists() && dir.isDirectory()) return dir; 692 693 694 695 throw new IOException("can't create/write to directory ["+dir+"], set \"init-param\" \"lucee-server-directory\" with path to writable directory"); 696 } 697 /** 698 * returns the path where the classloader is located 699 * @param cl ClassLoader 700 * @return file of the classloader root 701 */ 702 public static File getClassLoaderRoot(ClassLoader cl) { 703 String path="lucee/loader/engine/CFMLEngine.class"; 704 URL res = cl.getResource(path); 705 706 // get file and remove all after ! 707 String strFile=null; 708 try { 709 strFile = URLDecoder.decode(res.getFile().trim(),"iso-8859-1"); 710 } catch (UnsupportedEncodingException e) { 711 712 } 713 int index=strFile.indexOf('!'); 714 if(index!=-1)strFile=strFile.substring(0,index); 715 716 // remove path at the end 717 index=strFile.lastIndexOf(path); 718 if(index!=-1)strFile=strFile.substring(0,index); 719 720 // remove "file:" at start and lucee.jar at the end 721 if(strFile.startsWith("file:"))strFile=strFile.substring(5); 722 if(strFile.endsWith("lucee.jar")) strFile=strFile.substring(0,strFile.length()-9); 723 724 File file=new File(strFile); 725 if(file.isFile())file=file.getParentFile(); 726 727 return file; 728 } 729 730 /** 731 * check left value against right value 732 * @param left 733 * @param right 734 * @return returns if right is newer than left 735 */ 736 private boolean isNewerThan(int left, int right) { 737 return left>right; 738 } 739 740 /** 741 * Load CFMl Engine Implementation (lucee.runtime.engine.CFMLEngineImpl) from a Classloader 742 * @param classLoader 743 * @return loaded CFML Engine 744 * @throws ClassNotFoundException 745 * @throws NoSuchMethodException 746 * @throws SecurityException 747 * @throws InvocationTargetException 748 * @throws IllegalAccessException 749 * @throws IllegalArgumentException 750 */ 751 private CFMLEngine getEngine(ClassLoader classLoader) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { 752 Class clazz=classLoader.loadClass("lucee.runtime.engine.CFMLEngineImpl"); 753 Method m = clazz.getMethod("getInstance",new Class[]{CFMLEngineFactory.class}); 754 return (CFMLEngine) m.invoke(null,new Object[]{this}); 755 756 } 757 758 /** 759 * log info to output 760 * @param obj Object to output 761 */ 762 public void tlog(Object obj) { 763 log(new Date()+ " "+obj); 764 } 765 766 /** 767 * log info to output 768 * @param obj Object to output 769 */ 770 public void log(Object obj) { 771 if(out==null){ 772 boolean isCLI=false; 773 String str=System.getProperty("lucee.cli.call"); 774 if(!Util.isEmpty(str, true)) { 775 str=str.trim(); 776 isCLI="true".equalsIgnoreCase(str) || "yes".equalsIgnoreCase(str); 777 778 } 779 780 if(isCLI) { 781 try{ 782 File dir = new File(getResourceRoot(),"logs"); 783 dir.mkdirs(); 784 File file = new File(dir,"out"); 785 786 file.createNewFile(); 787 out=new PrintWriter(file); 788 } 789 catch(Throwable t){ 790 if(t instanceof ThreadDeath) throw (ThreadDeath)t; 791 t.printStackTrace(); 792 } 793 } 794 if(out==null)out=new PrintWriter(System.out); 795 } 796 out.write(""+obj+"\n"); 797 out.flush(); 798 } 799 800 private class UpdateChecker extends Thread { 801 private CFMLEngineFactory factory; 802 803 private UpdateChecker(CFMLEngineFactory factory) { 804 this.factory=factory; 805 } 806 807 public void run() { 808 long time=10000; 809 while(true) { 810 try { 811 sleep(time); 812 time=1000*60*60*24; 813 factory.update(); 814 815 } catch (Exception e) { 816 817 } 818 } 819 } 820 } 821 822}