/******************************************************************************* * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Exadel, Inc. and Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.resref.core; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.*; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IScopeContext; import org.eclipse.core.runtime.preferences.InstanceScope; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; public abstract class ResourceReferenceList { //Fix for JBIDE-2979 private static final String CODING = "UTF-16";//$NON-NLS-1$ ResourceReferenceListListener[] listeners = new ResourceReferenceListListener[0]; protected abstract QualifiedName getPropertyName(); public void addChangeListener(ResourceReferenceListListener listener) { int i = getListenerIndex(listener); if(i >= 0) return; ResourceReferenceListListener[] ls = new ResourceReferenceListListener[listeners.length + 1]; System.arraycopy(listeners, 0, ls, 0, listeners.length); ls[listeners.length] = listener; listeners = ls; } public void removeChangeListener(ResourceReferenceListListener listener) { int i = getListenerIndex(listener); if(i < 0) return; ResourceReferenceListListener[] ls = new ResourceReferenceListListener[listeners.length - 1]; if(i > 0) System.arraycopy(listeners, 0, ls, 0, i); if(i < ls.length) System.arraycopy(listeners, i + 1, ls, i, ls.length - i); listeners = ls; } private int getListenerIndex(ResourceReferenceListListener listener) { for (int i = 0; i < listeners.length; i++) { if(listeners[i] == listener) return i; } return -1; } /** * Returns all resources for current file * @param file * @return <code>ResourceReference</code> array that might be empty, never returns <code>null</code> */ public ResourceReference[] getAllResources(IFile file) { Set<String> locations = new HashSet<String>(); List<ResourceReference> css = new ArrayList<ResourceReference>(); if(file.getProject() != null) { String[] dcss = getDeclaredResources(file.getProject()); for (int i = 0; i < dcss.length; i++) { ResourceReference ref = new ResourceReference(dcss[i], ResourceReference.PROJECT_SCOPE); locations.add(dcss[i]); css.add(ref); } } IResource parent = file.getParent(); int depth = 0; while(parent instanceof IFolder) { String[] dcss = getDeclaredResources(parent); for (int i = 0; i < dcss.length; i++) { if(locations.contains(dcss[i])) continue; ResourceReference ref = new ResourceReference(dcss[i], ResourceReference.FOLDER_SCOPE); ref.setDepth(depth); locations.add(dcss[i]); css.add(ref); } parent = parent.getParent(); depth++; } String[] dcss = getDeclaredResources(file); for (int i = 0; i < dcss.length; i++) { if(locations.contains(dcss[i])) continue; ResourceReference ref = new ResourceReference(dcss[i], ResourceReference.FILE_SCOPE); locations.add(dcss[i]); css.add(ref); } return css.toArray(new ResourceReference[css.size()]); } private String[] getDeclaredResources(IResource resource) { /* * Property value */ String s = null; /* * https://jira.jboss.org/jira/browse/JBIDE-3211 * Reading preferences from project scope from .settings */ IScopeContext projectScope = new ProjectScope(resource.getProject()); IEclipsePreferences root = projectScope .getNode(ResourceReferencePlugin.PLUGIN_ID); if (root != null) { /* * Create subnode for file/folder/project */ IPath path = resource.getProjectRelativePath(); String nodeString = path.toString(); Preferences node = root.node(nodeString); if (null != node) { s = node.get(getPropertyName().getLocalName(), ""); //$NON-NLS-1$ } } if (s == null || s.length() == 0) { /* * Old preferences format property value. */ String old = null; try { old = resource.getPersistentProperty(getPropertyName()); } catch (CoreException e) { /* * Ignore, there is no properties for this resource. */ } if (old == null || old.length() == 0) { return new String[0]; } else { /* * If there is property stored in the old preferences format * return this value. */ return decodeResourceString(old); } } else { return decodeResourceString(s); } } //Fix for JBIDE-2979 private static String[] decodeResourceString(String resource) { String[] results = resource.split("[,;]"); String[] returnValues = new String [results.length]; try { for (int i=0;i<results.length;i++) { returnValues[i] = URLDecoder.decode(results[i].trim(), CODING); } } catch (UnsupportedEncodingException e) { ResourceReferencePlugin.getPluginLog().logError(e); //in case of exception we return undecoded values return results; } return returnValues; } public void setAllResources(IFile file, ResourceReference[] entries) { IResource changed = null; boolean b = setDeclaredResources(file, entries, ResourceReference.FILE_SCOPE, 0); if(b) changed = file; IResource parent = file.getParent(); int depth = 0; while(parent instanceof IFolder) { b = setDeclaredResources(parent, entries, ResourceReference.FOLDER_SCOPE, depth); if(b) { changed = parent; } parent = parent.getParent(); depth++; } if(file.getProject() != null) { int scope = ResourceReference.PROJECT_SCOPE; if(file.getParent() == file.getProject()) scope = 10; b = setDeclaredResources(file.getProject(), entries, scope, 0); if(b) { changed = file.getProject(); } } if(changed != null) fire(changed.getFullPath()); } private boolean setDeclaredResources(IResource resource, ResourceReference[] entries, int scope, int depth) { /* * https://jira.jboss.org/jira/browse/JBIDE-3211 * Storing project preferences to project scope in .settings */ IScopeContext projectScope = new ProjectScope(resource.getProject()); IEclipsePreferences root = projectScope .getNode(ResourceReferencePlugin.PLUGIN_ID); if (root != null) { /* * Get subnode for file/folder/project */ IPath path = resource.getProjectRelativePath(); String nodeString = path.toString(); Preferences node = root.node(nodeString); String oldValue = node.get(getPropertyName().getLocalName(), ""); //$NON-NLS-1$ String newValue = encodeDeclaredResources(entries, scope, depth); if (oldValue.equals(newValue)) { return false; } node.put(getPropertyName().getLocalName(), newValue); try { root.flush(); } catch (BackingStoreException e) { ResourceReferencePlugin.getPluginLog().logError(e); } } return true; } private String encodeDeclaredResources(ResourceReference[] entries, int scope, int depth) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < entries.length; i++) { int s = entries[i].getScope(); if(scope < 10 && s != scope) continue; if(scope == 10 && s == ResourceReference.FILE_SCOPE) continue; if(scope == ResourceReference.FOLDER_SCOPE && entries[i].getDepth() != depth) continue; if(sb.length() > 0) sb.append(';'); try { sb.append(URLEncoder.encode(entries[i].getLocationAndProperties(),CODING)); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return sb.toString(); } void fire(IPath path) { ResourceReferenceListListener[] ls = listeners; for (int i = 0; i < ls.length; i++) { IPath listenedPath = ls[i].getPath(); if(listenedPath != null && path.isPrefixOf(listenedPath)) { ls[i].changed(this); } } } /* * Handle opened external files */ TreeMap allExternalResources = null; private TreeMap getAllExternalResources() { if (allExternalResources == null) { allExternalResources = new TreeMap(); /* * Property value */ String s = null; /* * https://jira.jboss.org/jira/browse/JBIDE-3211 * Reading global preferences from instance scope. */ Preferences root = InstanceScope.INSTANCE.getNode(ResourceReferencePlugin.PREFERENCES_QUALIFIER); if (null != root) { Preferences node = root.node(ResourceReferencePlugin.PLUGIN_ID); s = node.get(getPropertyName().getLocalName(), ""); //$NON-NLS-1$ } /* * If there is property stored in the old preferences format and * there are no other properties old value will be returned */ if (s != null && s.length() > 0) { parseExternalResources(s); } else { /* * Old preferences format property value. */ String old = null; try { old =ResourcesPlugin.getWorkspace().getRoot() .getPersistentProperty(getPropertyName()); } catch (CoreException e) { /* * Ignore, there is no properties for this resource. */ } if (old != null && old.length() > 0) { parseExternalResources(old); } } } return allExternalResources; } private void parseExternalResources(String s) { StringTokenizer st = new StringTokenizer(s, "#"); //$NON-NLS-1$ while(st.hasMoreTokens()) { String t = st.nextToken(); int e = t.indexOf('='); String path = t.substring(0, e); String list = t.substring(e + 1); if(new File(path).exists()) { allExternalResources.put(path, list); } } } private void setAllExternalResources() { StringBuffer sb = new StringBuffer(); Iterator it = allExternalResources.keySet().iterator(); while (it.hasNext()) { String path = it.next().toString(); String list = (String) allExternalResources.get(path); if (path != null && list != null && new File(path).exists()) { if (sb.length() > 0) sb.append('#'); sb.append(path).append('=').append(list); } } /* * https://jira.jboss.org/jira/browse/JBIDE-3211 * Storing global preferences to instance scope to * ${workspace}\.metadata\.plugins\org.eclipse.core.runtime\ * .settings\org.jboss.tools.common.model.prefs */ Preferences root = InstanceScope.INSTANCE.getNode(ResourceReferencePlugin.PREFERENCES_QUALIFIER); if (null != root) { Preferences node = root.node(ResourceReferencePlugin.PLUGIN_ID); node.put(getPropertyName().getLocalName(), sb.toString()); try { root.flush(); } catch (BackingStoreException e) { ResourceReferencePlugin.getPluginLog().logError(e); } } } /** * * @param path * @return <code>ResourceReference</code> array that might be empty, never returns <code>null</code> */ public ResourceReference[] getAllResources(IPath path) { Set locations = new HashSet(); List css = new ArrayList(); IPath parent = path.removeLastSegments(1); int depth = 0; boolean isGlobal = path.equals(Platform.getLocation()); int setScope = isGlobal ? ResourceReference.GLOBAL_SCOPE : ResourceReference.FILE_SCOPE; while(parent != null && parent.segmentCount() > 1) { String[] dcss = getDeclaredResources(path); for (int i = 0; i < dcss.length; i++) { if(locations.contains(dcss[i])) continue; ResourceReference ref = new ResourceReference(dcss[i],isGlobal ? ResourceReference.GLOBAL_SCOPE : ResourceReference.FOLDER_SCOPE); if(isGlobal){ ref.setGlobal(true); } ref.setDepth(depth); locations.add(dcss[i]); css.add(ref); } parent = parent.removeLastSegments(1); depth++; } String[] dcss = getDeclaredResources(path); for (int i = 0; i < dcss.length; i++) { if(locations.contains(dcss[i])) continue; ResourceReference ref = new ResourceReference(dcss[i], setScope); if(setScope == ResourceReference.GLOBAL_SCOPE){ ref.setGlobal(true); } locations.add(dcss[i]); css.add(ref); } return (ResourceReference[])css.toArray(new ResourceReference[css.size()]); } private String[] getDeclaredResources(IPath path) { String s = (String)getAllExternalResources().get(path.toString()); if(s == null || s.length() == 0) { return new String[0]; }else { return decodeResourceString(s); } } public void setAllResources(IPath path, ResourceReference[] entries) { IPath changed = null; boolean b = false; int checkScope = path.equals(Platform.getLocation()) ? ResourceReference.GLOBAL_SCOPE : ResourceReference.FILE_SCOPE; b = setDeclaredResources(path, entries, checkScope, 0); if(b) { changed = path; } IPath parent = path.removeLastSegments(1); int depth = 0; while(parent != null && parent.segmentCount() > 1) { b = setDeclaredResources(parent, entries, ResourceReference.FOLDER_SCOPE, depth); if(b) { changed = parent; } parent = parent.removeLastSegments(1); depth++; } if(changed != null) { setAllExternalResources(); fire(changed); } } private boolean setDeclaredResources(IPath path, ResourceReference[] entries, int scope, int depth) { String oldValue = (String)getAllExternalResources().get(path.toString()); if(oldValue == null) { oldValue = ""; //$NON-NLS-1$ } String newValue = encodeDeclaredResources(entries, scope, depth); if(oldValue.equals(newValue)) return false; if(newValue == null || newValue.length() == 0) { getAllExternalResources().remove(path.toString()); } else { getAllExternalResources().put(path.toString(), newValue); } return true; } }