1 22 23 package org.gjt.sp.jedit; 24 25 import java.io.BufferedInputStream ; 27 import java.io.BufferedOutputStream ; 28 import java.io.DataInputStream ; 29 import java.io.DataOutputStream ; 30 import java.io.File ; 31 import java.io.FileInputStream ; 32 import java.io.FileNotFoundException ; 33 import java.io.FileOutputStream ; 34 import java.io.IOException ; 35 import java.io.InputStream ; 36 import java.lang.reflect.Modifier ; 37 import java.net.URL ; 38 import java.util.Enumeration ; 39 import java.util.LinkedHashSet ; 40 import java.util.LinkedList ; 41 import java.util.List ; 42 import java.util.Map ; 43 import java.util.Properties ; 44 import java.util.Set ; 45 import java.util.StringTokenizer ; 46 import java.util.zip.ZipEntry ; 47 import java.util.zip.ZipFile ; 48 49 import javax.swing.SwingUtilities ; 50 51 import org.gjt.sp.jedit.browser.VFSBrowser; 52 import org.gjt.sp.jedit.buffer.DummyFoldHandler; 53 import org.gjt.sp.jedit.buffer.FoldHandler; 54 import org.gjt.sp.jedit.gui.DockableWindowFactory; 55 import org.gjt.sp.jedit.msg.PluginUpdate; 56 import org.gjt.sp.util.Log; 57 import org.gjt.sp.util.PropertiesBean; 58 import org.gjt.sp.util.StandardUtilities; 59 import org.gjt.sp.util.IOUtilities; 60 62 128 public class PluginJAR 129 { 130 private final String path; 132 private String cachePath; 133 private final File file; 134 135 private final JARClassLoader classLoader; 136 private ZipFile zipFile; 137 private Properties properties; 138 private String [] classes; 139 private ActionSet actions; 140 private ActionSet browserActions; 141 private EditPlugin plugin; 142 private URL dockablesURI; 143 private URL servicesURI; 144 private boolean activated; 145 146 private final Set <String > theseRequireMe = new LinkedHashSet <String >(); 148 149 private final Set <String > theseUseMe = new LinkedHashSet <String >(); 150 private final Set <String > weRequireThese = new LinkedHashSet <String >(); 151 private final Set <String > weUseThese = new LinkedHashSet <String >(); 152 154 161 public static PluginJAR load(String path, boolean loadDependents) { 162 PluginJAR jar = jEdit.getPluginJAR(path); 163 if (jar != null && jar.getPlugin() != null) { 164 return jar; 165 } 166 jEdit.addPluginJAR(path); 167 jar = jEdit.getPluginJAR(path); 168 String className = jar.getPlugin().getClassName(); 169 if (loadDependents) { 170 Set <String > pluginLoadList = getDependencySet(className); 171 for (String jarName: pluginLoadList) 172 { 173 String jarPath = findPlugin(jarName); 174 load(jarPath, false); 175 } 176 } 177 String jars = jEdit.getProperty("plugin." + className + ".jars"); 179 if(jars != null) 180 { 181 String dir = MiscUtilities.getParentOfPath(path); 182 StringTokenizer st = new StringTokenizer (jars); 183 while(st.hasMoreTokens()) 184 { 185 String _jarPath = MiscUtilities.constructPath(dir,st.nextToken()); 186 PluginJAR _jar = jEdit.getPluginJAR(_jarPath); 187 if(_jar == null) 188 { 189 jEdit.addPluginJAR(_jarPath); 190 } 191 } 192 } 193 jar.checkDependencies(); 194 jar.activatePluginIfNecessary(); 195 return jar; 196 } 198 202 public String getPath() 203 { 204 return path; 205 } 207 217 public static String findPlugin(String className) 218 { 219 EditPlugin ep = jEdit.getPlugin(className); 220 if (ep != null) return ep.getPluginJAR().getPath(); 221 222 for (String JARpath: jEdit.getNotLoadedPluginJARs()) 223 { 224 PluginJAR pjar = new PluginJAR(new File (JARpath)); 225 if (pjar.containsClass(className)) 226 { 227 return JARpath; 228 } 229 } 230 return null; 231 } 233 239 boolean containsClass(String className) 240 { 241 try 242 { 243 getZipFile(); 244 } 245 catch (IOException ioe) { throw new RuntimeException (ioe);} 246 Enumeration itr = zipFile.entries(); 247 while (itr.hasMoreElements()) 248 { 249 String entry = itr.nextElement().toString(); 250 if (jarCompare(entry, className)) return true; 251 } 252 return false; 253 254 } 256 258 private static boolean jarCompare(String name1, String name2) 259 { 260 name1 = name1.replace('/','.'); 261 name2 = name2.replace('/','.'); 262 if (name1.contains(name2)) return true; 263 if (name2.contains(name1)) return true; 264 return false; 265 } 267 276 public String getCachePath() 277 { 278 return cachePath; 279 } 281 288 public static Set <String > getDependencySet(String className) { 289 String dep; 290 Set <String > retval = new LinkedHashSet <String >(); 291 int i=0; 292 while((dep = jEdit.getProperty("plugin." + className + ".depend." + i++)) != null) 293 { 294 PluginDepends pluginDepends; 295 try 296 { 297 pluginDepends = getPluginDepends(dep); 298 } 299 catch (IllegalArgumentException e) 300 { 301 Log.log(Log.ERROR, PluginJAR.class, 302 className + " has an invalid dependency: " + dep); 303 continue; 304 } 305 306 if(pluginDepends.what.equals("plugin")) 307 { 308 int index2 = pluginDepends.arg.indexOf(' '); 309 if ( index2 == -1) 310 { 311 Log.log(Log.ERROR, PluginJAR.class, className 312 + " has an invalid dependency: " 313 + dep + " (version is missing)"); 314 continue; 315 } 316 317 String pluginName = pluginDepends.arg.substring(0,index2); 318 String needVersion = pluginDepends.arg.substring(index2 + 1); 319 Set <String > loadTheseFirst = getDependencySet(pluginName); 321 loadTheseFirst.add(pluginName); 322 loadTheseFirst.addAll(retval); 323 retval = loadTheseFirst; 324 } 325 } 326 return retval; 327 } 329 333 public File getFile() 334 { 335 return file; 336 } 338 342 public JARClassLoader getClassLoader() 343 { 344 return classLoader; 345 } 347 352 public synchronized ZipFile getZipFile() throws IOException 353 { 354 if(zipFile == null) 355 { 356 Log.log(Log.DEBUG,this,"Opening " + path); 357 zipFile = new ZipFile (path); 358 } 359 return zipFile; 360 } 362 366 public ActionSet getActions() 367 { 368 return getActionSet(); 369 } 371 379 public ActionSet getActionSet() 380 { 381 return actions; 382 } 384 394 public ActionSet getBrowserActionSet() 395 { 396 return browserActions; 397 } 399 406 public boolean checkDependencies() 407 { 408 if(plugin == null) 409 return true; 410 int i = 0; 411 boolean ok = true; 412 413 String name = plugin.getClassName(); 414 415 String dep; 416 while((dep = jEdit.getProperty("plugin." + name + ".depend." + i++)) != null) 417 { 418 PluginDepends pluginDepends; 419 try 420 { 421 pluginDepends = getPluginDepends(dep); 422 } 423 catch (IllegalArgumentException e) 424 { 425 Log.log(Log.ERROR,this,name + " has an invalid" 426 + " dependency: " + dep); 427 ok = false; 428 continue; 429 } 430 431 if(pluginDepends.what.equals("jdk")) 432 { 433 if(!pluginDepends.optional && StandardUtilities.compareStrings( 434 System.getProperty("java.version"), 435 pluginDepends.arg,false) < 0) 436 { 437 String [] args = { pluginDepends.arg, 438 System.getProperty("java.version") }; 439 jEdit.pluginError(path,"plugin-error.dep-jdk",args); 440 ok = false; 441 } 442 } 443 else if(pluginDepends.what.equals("jedit")) 444 { 445 if(pluginDepends.arg.length() != 11) 446 { 447 Log.log(Log.ERROR,this,"Invalid jEdit version" 448 + " number: " + pluginDepends.arg); 449 ok = false; 450 } 451 452 if(!pluginDepends.optional && StandardUtilities.compareStrings( 453 jEdit.getBuild(),pluginDepends.arg,false) < 0) 454 { 455 String needs = MiscUtilities.buildToVersion(pluginDepends.arg); 456 String [] args = { needs, 457 jEdit.getVersion() }; 458 jEdit.pluginError(path, 459 "plugin-error.dep-jedit",args); 460 ok = false; 461 } 462 } 463 else if(pluginDepends.what.equals("plugin")) 464 { 465 int index2 = pluginDepends.arg.indexOf(' '); 466 if(index2 == -1) 467 { 468 Log.log(Log.ERROR,this,name 469 + " has an invalid dependency: " 470 + dep + " (version is missing)"); 471 ok = false; 472 continue; 473 } 474 475 String pluginName = pluginDepends.arg.substring(0,index2); 476 String needVersion = pluginDepends.arg.substring(index2 + 1); 477 String currVersion = jEdit.getProperty("plugin." 478 + pluginName + ".version"); 479 480 EditPlugin editPlugin = jEdit.getPlugin(pluginName, false); 481 if(editPlugin == null) 482 { 483 if(!pluginDepends.optional) 484 { 485 String [] args = { needVersion, 486 pluginName }; 487 jEdit.pluginError(path, 488 "plugin-error.dep-plugin.no-version", 489 args); 490 ok = false; 491 } 492 } 493 else if(StandardUtilities.compareStrings( 494 currVersion,needVersion,false) < 0) 495 { 496 if(!pluginDepends.optional) 497 { 498 String [] args = { needVersion, 499 pluginName, currVersion }; 500 jEdit.pluginError(path, "plugin-error.dep-plugin",args); 501 ok = false; 502 } 503 } 504 else if(editPlugin instanceof EditPlugin.Broken) 505 { 506 if(!pluginDepends.optional) 507 { 508 String [] args = { pluginName }; 509 jEdit.pluginError(path, "plugin-error.dep-plugin.broken",args); 510 ok = false; 511 } 512 } 513 else 514 { 515 PluginJAR jar = editPlugin.getPluginJAR(); 516 if (pluginDepends.optional) 517 { 518 jar.theseUseMe.add(path); 519 weUseThese.add(jar.getPath()); 520 } 521 else 522 { 523 jar.theseRequireMe.add(path); 524 weRequireThese.add(jar.getPath()); 525 } 526 } 527 } 528 else if(pluginDepends.what.equals("class")) 529 { 530 if(!pluginDepends.optional) 531 { 532 try 533 { 534 classLoader.loadClass(pluginDepends.arg,false); 535 } 536 catch(Exception e) 537 { 538 String [] args = { pluginDepends.arg }; 539 jEdit.pluginError(path, "plugin-error.dep-class",args); 540 ok = false; 541 } 542 } 543 } 544 else 545 { 546 Log.log(Log.ERROR,this,name + " has unknown" 547 + " dependency: " + dep); 548 ok = false; 549 } 550 } 551 552 String jars = jEdit.getProperty("plugin." 555 + plugin.getClassName() + ".jars"); 556 if(jars != null) 557 { 558 String dir = MiscUtilities.getParentOfPath(path); 559 560 StringTokenizer st = new StringTokenizer (jars); 561 while(st.hasMoreTokens()) 562 { 563 String jarPath = MiscUtilities.constructPath( 564 dir,st.nextToken()); 565 PluginJAR jar = jEdit.getPluginJAR(jarPath); 566 if(jar == null) 567 { 568 String [] args = { jarPath }; 569 jEdit.pluginError(path, "plugin-error.missing-jar",args); 570 ok = false; 571 } 572 else 573 { 574 weRequireThese.add(jarPath); 575 jar.theseRequireMe.add(path); 576 } 577 } 578 } 579 580 if(!ok) 581 breakPlugin(); 582 583 return ok; 584 } 586 private static PluginDepends getPluginDepends(String dep) throws IllegalArgumentException 587 { 588 boolean optional; 589 if(dep.startsWith("optional ")) 590 { 591 optional = true; 592 dep = dep.substring("optional ".length()); 593 } 594 else 595 { 596 optional = false; 597 } 598 599 int index = dep.indexOf(' '); 600 if(index == -1) 601 throw new IllegalArgumentException ("wrong dependency"); 602 603 String what = dep.substring(0,index); 604 String arg = dep.substring(index + 1); 605 PluginDepends depends = new PluginDepends(); 606 depends.what = what; 607 depends.arg = arg; 608 depends.optional = optional; 609 return depends; 610 } 611 private static class PluginDepends 612 { 613 String what; 614 String arg; 615 boolean optional; 616 } 617 618 628 public static void transitiveClosure(String [] dependents, List <String > listModel) 629 { 630 for(int i = 0; i < dependents.length; i++) 631 { 632 String jarPath = dependents[i]; 633 if(!listModel.contains(jarPath)) 634 { 635 listModel.add(jarPath); 636 PluginJAR jar = jEdit.getPluginJAR( 637 jarPath); 638 transitiveClosure(jar.getDependentPlugins(), 639 listModel); 640 } 641 } 642 } 644 645 646 public String [] getDependentPlugins() 648 { 649 return theseRequireMe.toArray(new String [theseRequireMe.size()]); 650 } 652 662 public EditPlugin getPlugin() 663 { 664 return plugin; 665 } 667 676 public void activatePlugin() 677 { 678 synchronized(this) 679 { 680 if(activated) 681 { 682 return; 684 } 685 686 activated = true; 687 } 688 689 if(!(plugin instanceof EditPlugin.Deferred)) 690 return; 691 692 String className = plugin.getClassName(); 693 694 try 695 { 696 Class clazz = classLoader.loadClass(className,false); 697 int modifiers = clazz.getModifiers(); 698 if(Modifier.isInterface(modifiers) 699 || Modifier.isAbstract(modifiers) 700 || !EditPlugin.class.isAssignableFrom(clazz)) 701 { 702 Log.log(Log.ERROR,this,"Plugin has properties but does not extend EditPlugin: " 703 + className); 704 breakPlugin(); 705 return; 706 } 707 708 plugin = (EditPlugin)clazz.newInstance(); 709 String settingsDirectory = jEdit.getSettingsDirectory(); 710 if (settingsDirectory != null) 711 { 712 File file = new File (settingsDirectory, "plugins"); 713 plugin.pluginHome = new File (file, className).getPath(); 714 } 715 plugin.jar = this; 716 } 717 catch(Throwable t) 718 { 719 breakPlugin(); 720 721 Log.log(Log.ERROR,this,"Error while starting plugin " + className); 722 Log.log(Log.ERROR,this,t); 723 String [] args = { t.toString() }; 724 jEdit.pluginError(path,"plugin-error.start-error",args); 725 726 return; 727 } 728 729 if(jEdit.isMainThread() 730 || SwingUtilities.isEventDispatchThread()) 731 { 732 startPlugin(); 733 } 734 else 735 { 736 startPluginLater(); 738 } 739 740 PropertiesBean.clearPropertyCache(); 741 EditBus.send(new PluginUpdate(this,PluginUpdate.ACTIVATED,false)); 742 } 744 749 public void activatePluginIfNecessary() 750 { 751 String filename = MiscUtilities.getFileName(getPath()); 752 jEdit.setBooleanProperty("plugin-blacklist." + filename, false); 753 if(!(plugin instanceof EditPlugin.Deferred && plugin != null)) 755 return; 756 757 String className = plugin.getClassName(); 758 759 String activate = jEdit.getProperty("plugin." 762 + className + ".activate"); 763 764 if(activate == null) 765 { 766 if(!jEdit.isMainThread()) 768 { 769 breakPlugin(); 770 771 jEdit.pluginError(path,"plugin-error.not-42",null); 772 } 773 else 774 activatePlugin(); 775 } 776 else 777 { 778 780 boolean load = false; 783 784 StringTokenizer st = new StringTokenizer (activate); 785 while(st.hasMoreTokens()) 786 { 787 String prop = st.nextToken(); 788 boolean value = jEdit.getBooleanProperty(prop); 789 if(value) 790 { 791 Log.log(Log.DEBUG,this,"Activating " 792 + className + " because of " + prop); 793 load = true; 794 break; 795 } 796 } 797 798 if(load) 799 activatePlugin(); 800 } 801 } 803 812 public void deactivatePlugin(boolean exit) 813 { 814 if(!activated) 815 return; 816 817 if(!exit) 818 { 819 Buffer buffer = jEdit.getFirstBuffer(); 823 while(buffer != null) 824 { 825 if(buffer.getFoldHandler() != null 826 && buffer.getFoldHandler().getClass() 827 .getClassLoader() == classLoader) 828 { 829 buffer.setFoldHandler( 830 new DummyFoldHandler()); 831 } 832 buffer = buffer.getNext(); 833 } 834 } 835 836 if(plugin != null && !(plugin instanceof EditPlugin.Broken)) 837 { 838 if(plugin instanceof EBPlugin) 839 EditBus.removeFromBus((EBPlugin)plugin); 840 841 try 842 { 843 plugin.stop(); 844 } 845 catch(Throwable t) 846 { 847 Log.log(Log.ERROR,this,"Error while " 848 + "stopping plugin:"); 849 Log.log(Log.ERROR,this,t); 850 } 851 852 plugin = new EditPlugin.Deferred(this, 853 plugin.getClassName()); 854 855 EditBus.send(new PluginUpdate(this, 856 PluginUpdate.DEACTIVATED,exit)); 857 858 if(!exit) 859 { 860 String activate = jEdit.getProperty("plugin." 862 + plugin.getClassName() + ".activate"); 863 864 if(activate == null) 865 { 866 breakPlugin(); 867 jEdit.pluginError(path,"plugin-error.not-42",null); 868 } 869 } 870 } 871 872 activated = false; 873 } 875 881 public URL getDockablesURI() 882 { 883 return dockablesURI; 884 } 886 892 public URL getServicesURI() 893 { 894 return servicesURI; 895 } 897 public String toString() 899 { 900 if(plugin == null) 901 return path; 902 else 903 return path + ",class=" + plugin.getClassName(); 904 } 906 908 910 static PluginCacheEntry getPluginCache(PluginJAR plugin) 912 { 913 String jarCachePath = plugin.getCachePath(); 914 if(jarCachePath == null) 915 return null; 916 917 DataInputStream din = null; 918 try 919 { 920 PluginCacheEntry cache = new PluginCacheEntry(); 921 cache.plugin = plugin; 922 cache.modTime = plugin.getFile().lastModified(); 923 din = new DataInputStream ( 924 new BufferedInputStream ( 925 new FileInputStream (jarCachePath))); 926 if(cache.read(din)) 927 return cache; 928 else 929 { 930 return null; 932 } 933 } 934 catch(FileNotFoundException fnf) 935 { 936 return null; 937 } 938 catch(IOException io) 939 { 940 Log.log(Log.ERROR,PluginJAR.class,io); 941 return null; 942 } 943 finally 944 { 945 IOUtilities.closeQuietly(din); 946 } 947 } 949 static void setPluginCache(PluginJAR plugin, PluginCacheEntry cache) 951 { 952 String jarCachePath = plugin.getCachePath(); 953 if(jarCachePath == null) 954 return; 955 956 Log.log(Log.DEBUG,PluginJAR.class,"Writing " + jarCachePath); 957 958 DataOutputStream dout = null; 959 try 960 { 961 dout = new DataOutputStream ( 962 new BufferedOutputStream ( 963 new FileOutputStream (jarCachePath))); 964 cache.write(dout); 965 dout.close(); 966 } 967 catch(IOException io) 968 { 969 Log.log(Log.ERROR,PluginJAR.class,io); 970 IOUtilities.closeQuietly(dout); 971 new File (jarCachePath).delete(); 972 } 973 } 975 977 982 public PluginJAR(File file) 983 { 984 this.path = file.getPath(); 985 String jarCacheDir = jEdit.getJARCacheDirectory(); 986 if(jarCacheDir != null) 987 { 988 cachePath = MiscUtilities.constructPath( 989 jarCacheDir,file.getName() + ".summary"); 990 } 991 this.file = file; 992 classLoader = new JARClassLoader(this); 993 actions = new ActionSet(); 994 } 996 void init() 998 { 999 1000 1001 PluginCacheEntry cache = getPluginCache(this); 1002 if(cache != null) 1003 { 1004 loadCache(cache); 1005 classLoader.activate(); 1006 } 1007 else 1008 { 1009 try 1010 { 1011 cache = generateCache(); 1012 if(cache != null) 1013 { 1014 setPluginCache(this,cache); 1015 classLoader.activate(); 1016 } 1017 } 1018 catch(IOException io) 1019 { 1020 Log.log(Log.ERROR,this,"Cannot load" 1021 + " plugin " + path); 1022 Log.log(Log.ERROR,this,io); 1023 1024 String [] args = { io.toString() }; 1025 jEdit.pluginError(path,"plugin-error.load-error",args); 1026 1027 uninit(false); 1028 } 1029 } 1030 } 1032 void uninit(boolean exit) 1034 { 1035 deactivatePlugin(exit); 1036 1037 if(!exit) 1038 { 1039 for (String path : weRequireThese) 1040 { 1041 PluginJAR jar = jEdit.getPluginJAR(path); 1042 if(jar != null) 1043 jar.theseRequireMe.remove(this.path); 1044 } 1045 1046 for (String path : weUseThese) 1047 { 1048 PluginJAR jar = jEdit.getPluginJAR(path); 1049 if(jar != null) 1050 jar.theseUseMe.remove(this.path); 1051 } 1052 1053 classLoader.deactivate(); 1054 BeanShell.resetClassManager(); 1055 1056 if(actions != null) 1057 jEdit.removeActionSet(actions); 1058 if(browserActions != null) 1059 VFSBrowser.getActionContext().removeActionSet(browserActions); 1060 1061 DockableWindowFactory.getInstance() 1062 .unloadDockableWindows(this); 1063 ServiceManager.unloadServices(this); 1064 1065 jEdit.removePluginProps(properties); 1066 1067 try 1068 { 1069 if(zipFile != null) 1070 { 1071 zipFile.close(); 1072 zipFile = null; 1073 } 1074 } 1075 catch(IOException io) 1076 { 1077 Log.log(Log.ERROR,this,io); 1078 } 1079 } 1080 } 1082 String [] getClasses() 1084 { 1085 return classes; 1086 } 1088 1090 1092 private void actionsPresentButNotCoreClass() 1094 { 1095 Log.log(Log.WARNING,this,getPath() + " has an actions.xml but no plugin core class"); 1096 actions.setLabel("MISSING PLUGIN CORE CLASS"); 1097 } 1099 private void loadCache(PluginCacheEntry cache) 1101 { 1102 classes = cache.classes; 1103 1104 1105 if(cache.cachedProperties != null) 1106 { 1107 properties = cache.cachedProperties; 1108 jEdit.addPluginProps(cache.cachedProperties); 1109 } 1110 1111 if(cache.actionsURI != null 1112 && cache.cachedActionNames != null) 1113 { 1114 actions = new ActionSet(this, 1115 cache.cachedActionNames, 1116 cache.cachedActionToggleFlags, 1117 cache.actionsURI); 1118 } 1119 1120 if(cache.browserActionsURI != null 1121 && cache.cachedBrowserActionNames != null) 1122 { 1123 browserActions = new ActionSet(this, 1124 cache.cachedBrowserActionNames, 1125 cache.cachedBrowserActionToggleFlags, 1126 cache.browserActionsURI); 1127 VFSBrowser.getActionContext().addActionSet(browserActions); 1128 } 1129 1130 if(cache.dockablesURI != null 1131 && cache.cachedDockableNames != null 1132 && cache.cachedDockableActionFlags != null) 1133 { 1134 dockablesURI = cache.dockablesURI; 1135 DockableWindowFactory.getInstance() 1136 .cacheDockableWindows(this, 1137 cache.cachedDockableNames, 1138 cache.cachedDockableActionFlags); 1139 } 1140 1141 if(actions.size() != 0) 1142 jEdit.addActionSet(actions); 1143 1144 if(cache.servicesURI != null 1145 && cache.cachedServices != null) 1146 { 1147 servicesURI = cache.servicesURI; 1148 for(int i = 0; i < cache.cachedServices.length; 1149 i++) 1150 { 1151 ServiceManager.Descriptor d 1152 = cache.cachedServices[i]; 1153 ServiceManager.registerService(d); 1154 } 1155 } 1156 1157 if(cache.pluginClass != null) 1158 { 1159 if(jEdit.getPlugin(cache.pluginClass) != null) 1162 { 1163 jEdit.pluginError(path, "plugin-error.already-loaded", 1164 null); 1165 uninit(false); 1166 } 1167 else 1168 { 1169 String label = jEdit.getProperty( 1170 "plugin." + cache.pluginClass 1171 + ".name"); 1172 actions.setLabel(jEdit.getProperty( 1173 "action-set.plugin", 1174 new String [] { label })); 1175 plugin = new EditPlugin.Deferred(this, 1176 cache.pluginClass); 1177 } 1178 } 1179 else 1180 { 1181 if(actions.size() != 0) 1182 actionsPresentButNotCoreClass(); 1183 } 1184 } 1186 private PluginCacheEntry generateCache() throws IOException 1188 { 1189 properties = new Properties (); 1190 1191 List <String > classes = new LinkedList <String >(); 1192 1193 ZipFile zipFile = getZipFile(); 1194 1195 List <String > plugins = new LinkedList <String >(); 1196 1197 PluginCacheEntry cache = new PluginCacheEntry(); 1198 cache.modTime = file.lastModified(); 1199 cache.cachedProperties = new Properties (); 1200 1201 Enumeration <? extends ZipEntry > entries = zipFile.entries(); 1202 while(entries.hasMoreElements()) 1203 { 1204 ZipEntry entry = entries.nextElement(); 1205 String name = entry.getName(); 1206 String lname = name.toLowerCase(); 1207 if(lname.equals("actions.xml")) 1208 { 1209 cache.actionsURI = classLoader.getResource(name); 1210 } 1211 else if(lname.equals("browser.actions.xml")) 1212 { 1213 cache.browserActionsURI = classLoader.getResource(name); 1214 } 1215 else if(lname.equals("dockables.xml")) 1216 { 1217 dockablesURI = classLoader.getResource(name); 1218 cache.dockablesURI = dockablesURI; 1219 } 1220 else if(lname.equals("services.xml")) 1221 { 1222 servicesURI = classLoader.getResource(name); 1223 cache.servicesURI = servicesURI; 1224 } 1225 else if(lname.endsWith(".props")) 1226 { 1227 InputStream in = classLoader.getResourceAsStream(name); 1228 properties.load(in); 1229 in.close(); 1230 } 1231 else if(name.endsWith(".class")) 1232 { 1233 String className = MiscUtilities 1234 .fileToClass(name); 1235 if(className.endsWith("Plugin")) 1236 { 1237 plugins.add(className); 1238 } 1239 classes.add(className); 1240 } 1241 } 1242 1243 cache.cachedProperties = properties; 1244 jEdit.addPluginProps(properties); 1245 1246 this.classes = cache.classes = 1247 classes.toArray( 1248 new String [classes.size()]); 1249 1250 String label = null; 1251 1252 for (String className : plugins) 1253 { 1254 String _label = jEdit.getProperty("plugin." 1255 + className + ".name"); 1256 String version = jEdit.getProperty("plugin." 1257 + className + ".version"); 1258 if(_label == null || version == null) 1259 { 1260 Log.log(Log.WARNING,this,"Ignoring: " 1261 + className); 1262 } 1263 else 1264 { 1265 cache.pluginClass = className; 1266 1267 if(jEdit.getPlugin(className) != null) 1270 { 1271 jEdit.pluginError(path, "plugin-error.already-loaded", 1272 null); 1273 return null; 1274 } 1275 plugin = new EditPlugin.Deferred(this, 1276 className); 1277 label = _label; 1278 1279 break; 1280 } 1281 } 1282 1283 if(cache.actionsURI != null) 1284 { 1285 actions = new ActionSet(this,null,null, 1286 cache.actionsURI); 1287 actions.load(); 1288 cache.cachedActionNames = 1289 actions.getCacheableActionNames(); 1290 cache.cachedActionToggleFlags = 1291 new boolean[cache.cachedActionNames.length]; 1292 for(int i = 0; i < cache.cachedActionNames.length; i++) 1293 { 1294 cache.cachedActionToggleFlags[i] = 1295 jEdit.getBooleanProperty( 1296 cache.cachedActionNames[i] + ".toggle"); 1297 } 1298 } 1299 1300 if(cache.browserActionsURI != null) 1301 { 1302 browserActions = 1303 new ActionSet(this,null,null, cache.browserActionsURI); 1304 browserActions.load(); 1305 VFSBrowser.getActionContext().addActionSet(browserActions); 1306 cache.cachedBrowserActionNames = 1307 browserActions.getCacheableActionNames(); 1308 cache.cachedBrowserActionToggleFlags = new boolean[ 1309 cache.cachedBrowserActionNames.length]; 1310 for(int i = 0; 1311 i < cache.cachedBrowserActionNames.length; i++) 1312 { 1313 cache.cachedBrowserActionToggleFlags[i] 1314 = jEdit.getBooleanProperty( 1315 cache.cachedBrowserActionNames[i] + ".toggle"); 1316 } 1317 } 1318 1319 if(dockablesURI != null) 1320 { 1321 DockableWindowFactory.getInstance() 1322 .loadDockableWindows(this, dockablesURI,cache); 1323 } 1324 1325 if(actions.size() != 0) 1326 { 1327 if(label != null) 1328 { 1329 actions.setLabel(jEdit.getProperty( 1330 "action-set.plugin", new String [] { label })); 1331 } 1332 else 1333 actionsPresentButNotCoreClass(); 1334 1335 jEdit.addActionSet(actions); 1336 } 1337 1338 if(servicesURI != null) 1339 { 1340 ServiceManager.loadServices(this,servicesURI,cache); 1341 } 1342 1343 return cache; 1344 } 1346 private void startPlugin() 1348 { 1349 try 1350 { 1351 plugin.start(); 1352 } 1353 catch(Throwable t) 1354 { 1355 breakPlugin(); 1356 1357 Log.log(Log.ERROR,PluginJAR.this, 1358 "Error while starting plugin " + plugin.getClassName()); 1359 Log.log(Log.ERROR,PluginJAR.this,t); 1360 String [] args = { t.toString() }; 1361 jEdit.pluginError(path, "plugin-error.start-error",args); 1362 } 1363 1364 if(plugin instanceof EBPlugin) 1365 { 1366 if(jEdit.getProperty("plugin." + plugin.getClassName() 1367 + ".activate") == null) 1368 { 1369 ((EBComponent)plugin).handleMessage( 1373 new org.gjt.sp.jedit.msg.PropertiesChanged(null)); 1374 } 1375 EditBus.addToBus((EBPlugin)plugin); 1376 } 1377 1378 Buffer buffer = jEdit.getFirstBuffer(); 1382 while(buffer != null) 1383 { 1384 FoldHandler handler = 1385 FoldHandler.getFoldHandler( 1386 buffer.getStringProperty("folding")); 1387 if(buffer.getFoldHandler() != null 1389 && handler != null 1390 && handler != buffer.getFoldHandler()) 1391 { 1392 buffer.setFoldHandler(handler); 1393 } 1394 buffer = buffer.getNext(); 1395 } 1396 } 1398 private void startPluginLater() 1400 { 1401 SwingUtilities.invokeLater(new Runnable () 1402 { 1403 public void run() 1404 { 1405 if(!activated) 1406 return; 1407 1408 startPlugin(); 1409 } 1410 }); 1411 } 1413 private void breakPlugin() 1415 { 1416 plugin = new EditPlugin.Broken(this,plugin.getClassName()); 1417 1418 uninit(false); 1421 jEdit.addPluginProps(properties); 1423 } 1425 1427 1433 public static class PluginCacheEntry 1434 { 1435 public static final int MAGIC = 0xB7A2E420; 1436 1437 public PluginJAR plugin; 1439 public long modTime; 1440 1441 public String [] classes; 1442 public URL actionsURI; 1443 public String [] cachedActionNames; 1444 public boolean[] cachedActionToggleFlags; 1445 public URL browserActionsURI; 1446 public String [] cachedBrowserActionNames; 1447 public boolean[] cachedBrowserActionToggleFlags; 1448 public URL dockablesURI; 1449 public String [] cachedDockableNames; 1450 public boolean[] cachedDockableActionFlags; 1451 public URL servicesURI; 1452 ServiceManager.Descriptor[] cachedServices; 1453 1454 public Properties cachedProperties; 1455 public String pluginClass; 1456 1458 1462 1463 public boolean read(DataInputStream din) throws IOException 1465 { 1466 int cacheMagic = din.readInt(); 1467 if(cacheMagic != MAGIC) 1468 return false; 1469 1470 String cacheBuild = readString(din); 1471 if(!cacheBuild.equals(jEdit.getBuild())) 1472 return false; 1473 1474 long cacheModTime = din.readLong(); 1475 if(cacheModTime != modTime) 1476 return false; 1477 1478 actionsURI = readURI(din); 1479 cachedActionNames = readStringArray(din); 1480 cachedActionToggleFlags = readBooleanArray(din); 1481 1482 browserActionsURI = readURI(din); 1483 cachedBrowserActionNames = readStringArray(din); 1484 cachedBrowserActionToggleFlags = readBooleanArray(din); 1485 1486 dockablesURI = readURI(din); 1487 cachedDockableNames = readStringArray(din); 1488 cachedDockableActionFlags = readBooleanArray(din); 1489 1490 servicesURI = readURI(din); 1491 int len = din.readInt(); 1492 if(len == 0) 1493 cachedServices = null; 1494 else 1495 { 1496 cachedServices = new ServiceManager.Descriptor[len]; 1497 for(int i = 0; i < len; i++) 1498 { 1499 ServiceManager.Descriptor d = new 1500 ServiceManager.Descriptor( 1501 readString(din), 1502 readString(din), 1503 null, 1504 plugin); 1505 cachedServices[i] = d; 1506 } 1507 } 1508 1509 classes = readStringArray(din); 1510 1511 cachedProperties = readMap(din); 1512 1513 pluginClass = readString(din); 1514 1515 return true; 1516 } 1518 public void write(DataOutputStream dout) throws IOException 1520 { 1521 dout.writeInt(MAGIC); 1522 writeString(dout,jEdit.getBuild()); 1523 1524 dout.writeLong(modTime); 1525 1526 writeString(dout,actionsURI); 1527 writeStringArray(dout,cachedActionNames); 1528 writeBooleanArray(dout,cachedActionToggleFlags); 1529 1530 writeString(dout,browserActionsURI); 1531 writeStringArray(dout,cachedBrowserActionNames); 1532 writeBooleanArray(dout,cachedBrowserActionToggleFlags); 1533 1534 writeString(dout,dockablesURI); 1535 writeStringArray(dout,cachedDockableNames); 1536 writeBooleanArray(dout,cachedDockableActionFlags); 1537 1538 writeString(dout,servicesURI); 1539 if(cachedServices == null) 1540 dout.writeInt(0); 1541 else 1542 { 1543 dout.writeInt(cachedServices.length); 1544 for(int i = 0; i < cachedServices.length; i++) 1545 { 1546 writeString(dout,cachedServices[i].clazz); 1547 writeString(dout,cachedServices[i].name); 1548 } 1549 } 1550 1551 writeStringArray(dout,classes); 1552 1553 writeMap(dout,cachedProperties); 1554 1555 writeString(dout,pluginClass); 1556 } 1558 1560 private static String readString(DataInputStream din) 1562 throws IOException 1563 { 1564 int len = din.readInt(); 1565 if(len == 0) 1566 return null; 1567 char[] str = new char[len]; 1568 for(int i = 0; i < len; i++) 1569 str[i] = din.readChar(); 1570 return new String (str); 1571 } 1573 private static URL readURI(DataInputStream din) 1575 throws IOException 1576 { 1577 String str = readString(din); 1578 if(str == null) 1579 return null; 1580 else 1581 return new URL (str); 1582 } 1584 private static String [] readStringArray(DataInputStream din) 1586 throws IOException 1587 { 1588 int len = din.readInt(); 1589 if(len == 0) 1590 return null; 1591 String [] str = new String [len]; 1592 for(int i = 0; i < len; i++) 1593 { 1594 str[i] = readString(din); 1595 } 1596 return str; 1597 } 1599 private static boolean[] readBooleanArray(DataInputStream din) 1601 throws IOException 1602 { 1603 int len = din.readInt(); 1604 if(len == 0) 1605 return null; 1606 boolean[] bools = new boolean[len]; 1607 for(int i = 0; i < len; i++) 1608 { 1609 bools[i] = din.readBoolean(); 1610 } 1611 return bools; 1612 } 1614 private static Properties readMap(DataInputStream din) 1616 throws IOException 1617 { 1618 Properties returnValue = new Properties (); 1619 int count = din.readInt(); 1620 for(int i = 0; i < count; i++) 1621 { 1622 String key = readString(din); 1623 String value = readString(din); 1624 if(value == null) 1625 value = ""; 1626 returnValue.put(key,value); 1627 } 1628 return returnValue; 1629 } 1631 private static void writeString(DataOutputStream dout, 1633 Object obj) throws IOException 1634 { 1635 if(obj == null) 1636 { 1637 dout.writeInt(0); 1638 } 1639 else 1640 { 1641 String str = obj.toString(); 1642 dout.writeInt(str.length()); 1643 dout.writeChars(str); 1644 } 1645 } 1647 private static void writeStringArray(DataOutputStream dout, 1649 String [] str) throws IOException 1650 { 1651 if(str == null) 1652 { 1653 dout.writeInt(0); 1654 } 1655 else 1656 { 1657 dout.writeInt(str.length); 1658 for(int i = 0; i < str.length; i++) 1659 { 1660 writeString(dout,str[i]); 1661 } 1662 } 1663 } 1665 private static void writeBooleanArray(DataOutputStream dout, 1667 boolean[] bools) throws IOException 1668 { 1669 if(bools == null) 1670 { 1671 dout.writeInt(0); 1672 } 1673 else 1674 { 1675 dout.writeInt(bools.length); 1676 for(int i = 0; i < bools.length; i++) 1677 { 1678 dout.writeBoolean(bools[i]); 1679 } 1680 } 1681 } 1683 private static void writeMap(DataOutputStream dout, Map map) 1685 throws IOException 1686 { 1687 dout.writeInt(map.size()); 1688 Set <Map.Entry <Object , Object >> set = map.entrySet(); 1689 for (Map.Entry <Object , Object > entry : set) 1690 { 1691 writeString(dout,entry.getKey()); 1692 writeString(dout,entry.getValue()); 1693 } 1694 } 1696 } } 1699 | Popular Tags |