1 19 20 package org.netbeans.modules.editor.mimelookup.impl; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.util.ArrayList ; 25 import java.util.HashMap ; 26 import java.util.HashSet ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.Set ; 30 import java.util.logging.Logger ; 31 import org.netbeans.api.editor.mimelookup.MimePath; 32 import org.netbeans.spi.editor.mimelookup.InstanceProvider; 33 import org.openide.util.Lookup; 34 import org.openide.util.WeakListeners; 35 import org.openide.util.lookup.ProxyLookup; 36 37 41 public class SwitchLookup extends Lookup { 42 43 private static final Logger LOG = Logger.getLogger(SwitchLookup.class.getName()); 44 45 static final String ROOT_FOLDER = "Editors"; 47 private MimePath mimePath; 48 49 private final String LOCK = new String ("SwitchLookup.LOCK"); 51 private MappingListener listener; 52 53 private HashMap classLookups = new HashMap (); 54 private HashMap pathsLookups = new HashMap (); 55 56 private HashMap classInfos = new HashMap (); 57 private HashMap pathsToClasses = new HashMap (); 58 59 60 public SwitchLookup(MimePath mimePath) { 61 super(); 62 63 this.mimePath = mimePath; 64 65 this.listener = new MappingListener(); 66 ClassInfoStorage.getInstance().addPropertyChangeListener( 67 WeakListeners.propertyChange(listener, ClassInfoStorage.getInstance())); 68 } 69 70 public Lookup.Result lookup(Lookup.Template template) { 71 return findLookup(template.getType()).lookup(template); 72 } 73 74 public Object lookup(Class clazz) { 75 return findLookup(clazz).lookup(clazz); 76 } 77 78 private Lookup findLookup(Class clazz) { 79 synchronized (LOCK) { 80 String className = clazz.getName(); 81 Lookup lookup = (Lookup) classLookups.get(className); 82 if (lookup == null) { 83 ClassInfoStorage.Info classInfo = ClassInfoStorage.getInstance().getInfo(className); 85 classInfos.put(className, classInfo); 86 87 Lookup innerLookup = createLookup(classInfo); 89 lookup = new UpdatableProxyLookup(new Lookup [] { innerLookup }); 90 91 classLookups.put(className, lookup); 92 } 93 94 return lookup; 95 } 96 } 97 98 private Lookup createLookup(ClassInfoStorage.Info classInfo) { 99 List paths = computePaths(mimePath, ROOT_FOLDER, classInfo.getExtraPath()); 100 Lookup lookup; 101 102 if (classInfo.getInstanceProviderClass() != null) { 103 lookup = getLookupForProvider(classInfo.getClassName(), paths, classInfo.getInstanceProvider()); 105 } else { 106 Set pathsUsers = (Set ) pathsToClasses.get(paths); 108 if (pathsUsers == null) { 109 pathsUsers = new HashSet (); 110 pathsToClasses.put(paths, pathsUsers); 111 } 112 pathsUsers.add(classInfo.getClassName()); 113 114 lookup = getLookupForPaths(paths); 116 } 117 118 return lookup; 119 } 120 121 private Lookup getLookupForPaths(List paths) { 122 Lookup lookup = (Lookup) pathsLookups.get(paths); 123 if (lookup == null) { 124 lookup = new FolderPathLookup((String []) paths.toArray(new String [paths.size()])); 125 pathsLookups.put(paths, lookup); 126 } 127 128 return lookup; 129 } 130 131 private Lookup getLookupForProvider(String className, List paths, InstanceProvider instanceProvider) { 132 return new InstanceProviderLookup((String [])paths.toArray(new String [paths.size()]), instanceProvider); 133 } 134 135 private void rebuildLookup(String className) { 136 synchronized (LOCK) { 137 UpdatableProxyLookup classLookup = (UpdatableProxyLookup) classLookups.get(className); 138 if (classLookup == null) { 139 return; 141 } 142 143 ClassInfoStorage.Info currentClassInfo = (ClassInfoStorage.Info) classInfos.get(className); 144 ClassInfoStorage.Info classInfo = ClassInfoStorage.getInstance().getInfo(className); 145 146 if (currentClassInfo.equals(classInfo)) { 147 return; 149 } 150 151 if (currentClassInfo.getInstanceProviderClass() == null) { 152 List currentPaths = computePaths(mimePath, ROOT_FOLDER, currentClassInfo.getExtraPath()); 153 154 Set currentPathsUsers = (Set ) pathsToClasses.get(currentPaths); 156 currentPathsUsers.remove(className); 157 158 if (currentPathsUsers.isEmpty()) { 159 pathsToClasses.remove(currentPaths); 160 pathsLookups.remove(currentPaths); 161 } 162 } 163 164 classInfos.put(className, classInfo); 166 167 Lookup innerLookup = createLookup(classInfo); 169 classLookup.setLookupsEx(new Lookup [] { innerLookup }); 170 } 171 } 172 173 177 static List computePaths(MimePath mimePath, String prefixPath, String suffixPath) { 178 ArrayList arrays = new ArrayList (mimePath.size()); 179 String innerMimeType = null; 180 181 if (mimePath.size() > 1) { 182 innerMimeType = mimePath.getMimeType(mimePath.size() - 1); 183 } 184 185 for (int i = mimePath.size(); i >= 0 ; i--) { 186 MimePath currentPath = mimePath.getPrefix(i); 187 188 if (currentPath.size() != 1 || innerMimeType == null || 191 !currentPath.getMimeType(0).equals(innerMimeType) 192 ) { 193 arrays.add(split(currentPath)); 195 } 196 197 if (currentPath.size() > 0) { 201 String mimeType = currentPath.getMimeType(currentPath.size() - 1); 202 String genericMimeType = getGenericPartOfCompoundMimeType(mimeType); 203 204 if (genericMimeType != null) { 205 List genericPaths = forkPaths(arrays, genericMimeType, i - 1); 206 arrays.addAll(genericPaths); 207 } 208 } 209 } 210 211 if (innerMimeType != null) { 213 arrays.add(1, new String [] { innerMimeType }); 214 215 String genericInnerMimeType = getGenericPartOfCompoundMimeType(innerMimeType); 216 if (genericInnerMimeType != null) { 217 arrays.add(2, new String [] { genericInnerMimeType }); 218 } 219 } 220 221 ArrayList paths = new ArrayList (arrays.size()); 222 223 for (Iterator i = arrays.iterator(); i.hasNext(); ) { 224 String [] path = (String []) i.next(); 225 StringBuffer sb = new StringBuffer (10 * path.length + 20); 226 227 if (prefixPath != null && prefixPath.length() > 0) { 228 sb.append(prefixPath); 229 } 230 for (int ii = 0; ii < path.length; ii++) { 231 if (path[ii].length() > 0) { 232 if (sb.length() > 0) { 233 sb.append('/'); } 235 sb.append(path[ii]); 236 } 237 } 238 if (suffixPath != null && suffixPath.length() > 0) { 239 if (sb.length() > 0) { 240 sb.append('/'); } 242 sb.append(suffixPath); 243 } 244 245 paths.add(sb.toString()); 246 } 247 248 return paths; 249 } 250 251 static String getGenericPartOfCompoundMimeType(String mimeType) { 255 int plusIdx = mimeType.lastIndexOf('+'); if (plusIdx != -1 && plusIdx < mimeType.length() - 1) { 257 int slashIdx = mimeType.indexOf('/'); String prefix = mimeType.substring(0, slashIdx + 1); 259 String suffix = mimeType.substring(plusIdx + 1); 260 261 if (suffix.equals("xml")) { prefix = "text/"; } 265 266 return prefix + suffix; 267 } else { 268 return null; 269 } 270 } 271 272 private static String [] split(MimePath mimePath) { 273 String [] array = new String [mimePath.size()]; 274 275 for (int i = 0; i < mimePath.size(); i++) { 276 array[i] = mimePath.getMimeType(i); 277 } 278 279 return array; 280 } 281 282 private static List forkPaths(List paths, String genericMimeType, int elementIdx) { 285 ArrayList forkedPaths = new ArrayList (paths.size()); 286 287 for (Iterator i = paths.iterator(); i.hasNext(); ) { 288 String [] path = (String []) i.next(); 289 String [] forkedPath = new String [path.length]; 290 291 for (int ii = 0; ii < path.length; ii++) { 292 if (ii != elementIdx) { 293 forkedPath[ii] = path[ii]; 294 } else { 295 forkedPath[ii] = genericMimeType; 296 } 297 } 298 299 forkedPaths.add(forkedPath); 300 } 301 302 return forkedPaths; 303 } 304 305 309 private static final class UpdatableProxyLookup extends ProxyLookup { 310 public UpdatableProxyLookup() { 311 super(); 312 } 313 314 public UpdatableProxyLookup(Lookup [] lookups) { 315 super(lookups); 316 } 317 318 public void setLookupsEx(Lookup [] lookups) { 319 setLookups(lookups); 320 } 321 } 323 private final class MappingListener implements PropertyChangeListener { 324 public void propertyChange(PropertyChangeEvent evt) { 325 Set classNames = (Set )evt.getNewValue(); 326 327 for (Iterator i = classNames.iterator(); i.hasNext(); ) { 328 String className = (String ) i.next(); 329 rebuildLookup(className); 330 } 331 } 332 } 334 } 335 | Popular Tags |