/******************************************************************************* * Copyright (c) 2007, 2010 Spring IDE Developers * All rights reserved. This program and the accompanying materials * are 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: * Spring IDE Developers - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.beans.ui.namespaces; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.Preferences; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.core.JarEntryFile; import org.eclipse.swt.graphics.Image; import org.springframework.ide.eclipse.beans.core.BeansCorePlugin; import org.springframework.ide.eclipse.beans.ui.BeansUIImages; import org.springframework.ide.eclipse.core.SpringCorePreferences; import org.springframework.ide.eclipse.core.java.JdtUtils; import org.springframework.util.StringUtils; /** * Default implementation of {@link INamespaceDefinition}. * @author Christian Dupuis * @since 2.0 */ @SuppressWarnings({ "deprecation", "restriction" }) public class DefaultNamespaceDefinition implements INamespaceDefinition { public static final Pattern VERSION_PATTERN = Pattern.compile(".*-([0-9,.]*)\\.xsd"); private final String defaultLocation; private final IImageAccessor imageAccessor; private Set<String> locations = new HashSet<String>(); private final String defaultPrefix; private final String uri; private Properties uriMapping = new Properties(); public DefaultNamespaceDefinition(String prefix, String uri, String defaultLocation, IImageAccessor imageAccessor) { this(prefix, uri, defaultLocation, new Properties(), imageAccessor); } public DefaultNamespaceDefinition(String prefix, String uri, String defaultLocation, final Image image) { this(prefix, uri, defaultLocation, new IImageAccessor() { public Image getImage() { return image; } }); } public DefaultNamespaceDefinition(String prefix, String uri, String defaultLocation, Properties namespaceDefinition, IImageAccessor imageAccessor) { if (prefix != null) { this.defaultPrefix = prefix; } else { int ix = uri.lastIndexOf('/'); this.defaultPrefix = uri.substring(ix + 1); } this.uri = uri; this.defaultLocation = defaultLocation; this.uriMapping = namespaceDefinition; this.imageAccessor = imageAccessor; } public void addSchemaLocation(String location) { locations.add(location); } /** * {@inheritDoc} */ public boolean equals(Object obj) { if (obj instanceof DefaultNamespaceDefinition) { DefaultNamespaceDefinition o = (DefaultNamespaceDefinition) obj; return o.defaultPrefix.equals(defaultPrefix) && o.uri.equals(uri); } return false; } public String getDefaultNamespacePrefix() { return defaultPrefix; } public String getDefaultSchemaLocation() { return getDefaultSchemaLocation(null); } /** * {@inheritDoc} */ public String getDefaultSchemaLocation(IResource resource) { String location = null; if (hasProjectSpecificOptions(resource)) { SpringCorePreferences prefs = SpringCorePreferences.getProjectPreferences(resource.getProject(), BeansCorePlugin.PLUGIN_ID); if (prefs.getBoolean(BeansCorePlugin.NAMESPACE_DEFAULT_FROM_CLASSPATH_ID, true)) { location = getDefaultSchemaLocationFromClasspath(resource); } if ("".equals(location) || location == null) { location = prefs.getString(BeansCorePlugin.NAMESPACE_DEFAULT_VERSION_PREFERENCE_ID + getNamespaceURI(), ""); } } else { Preferences prefs = BeansCorePlugin.getDefault().getPluginPreferences(); if (prefs.getBoolean(BeansCorePlugin.NAMESPACE_DEFAULT_FROM_CLASSPATH_ID)) { location = getDefaultSchemaLocationFromClasspath(resource); } if ("".equals(location) || location == null) { location = prefs.getString(BeansCorePlugin.NAMESPACE_DEFAULT_VERSION_PREFERENCE_ID + getNamespaceURI()); } } if ("".equals(location) || location == null) { return defaultLocation; } else { return location; } } /** * {@inheritDoc} */ public Image getNamespaceImage() { if (imageAccessor != null) { return imageAccessor.getImage(); } return BeansUIImages.getImage(BeansUIImages.IMG_OBJS_XSD); } /** * {@inheritDoc} */ public String getNamespacePrefix() { return defaultPrefix; } /** * {@inheritDoc} */ public String getNamespacePrefix(IResource resource) { String prefix = null; if (hasProjectSpecificOptions(resource)) { SpringCorePreferences prefs = SpringCorePreferences.getProjectPreferences(resource.getProject(), BeansCorePlugin.PLUGIN_ID); prefix = prefs.getString(BeansCorePlugin.NAMESPACE_PREFIX_PREFERENCE_ID + getNamespaceURI(), ""); } else { Preferences prefs = BeansCorePlugin.getDefault().getPluginPreferences(); prefix = prefs.getString(BeansCorePlugin.NAMESPACE_PREFIX_PREFERENCE_ID + getNamespaceURI()); } if (StringUtils.hasLength(prefix)) { return prefix; } return defaultPrefix; } /** * {@inheritDoc} */ public String getNamespaceURI() { return uri; } /** * {@inheritDoc} */ public Set<String> getSchemaLocations() { return locations; } /** * {@inheritDoc} */ public int hashCode() { return defaultPrefix.hashCode() ^ uri.hashCode(); } private String getDefaultSchemaLocationFromClasspath(IResource resource) { IJavaProject jp = JdtUtils.getJavaProject(resource); Set<String> existingLocations = new HashSet<String>(); try { for (Map.Entry<Object, Object> entry : uriMapping.entrySet()) { // Check that we are looking for relevant entries only; e.g. util, tool and beans are in the same // package if (((String) entry.getKey()).startsWith(uri)) { String fileLocation = (String) entry.getValue(); // Get the package name from the location String packageName = ""; int ix = fileLocation.lastIndexOf('/'); if (ix > 0) { packageName = fileLocation.substring(0, ix).replace('/', '.'); } // Search in all project packages for (IPackageFragmentRoot root : jp.getPackageFragmentRoots()) { IPackageFragment pf = root.getPackageFragment(packageName); if (pf.exists()) { for (Object obj : pf.getNonJavaResources()) { // Entry is coming from a JAR file on the classpath if (obj instanceof JarEntryFile && ("/" + fileLocation).equals((((JarEntryFile) obj).getFullPath().toString())) && locations.contains(entry.getKey())) { existingLocations.add((String) entry.getKey()); } // Entry is coming from the local project else if (obj instanceof IFile && fileLocation.equals(pf.getElementName().replace('.', '/') + "/" + ((IFile) obj).getName()) && locations.contains(entry.getKey())) { existingLocations.add((String) entry.getKey()); } } } } } } } catch (JavaModelException e) { // We have a safe fall-back } // Search for the highest version among the existing resources String highestLocation = null; Version version = Version.MINIMUM_VERSION; for (String location : existingLocations) { Version tempVersion = Version.MINIMUM_VERSION; Matcher matcher = VERSION_PATTERN.matcher(location); if (matcher.matches()) { tempVersion = new Version(matcher.group(1)); } if (tempVersion.compareTo(version) >= 0) { version = tempVersion; highestLocation = location; } } return highestLocation; } private boolean hasProjectSpecificOptions(IResource resource) { if (resource == null) { return false; } return SpringCorePreferences.getProjectPreferences(resource.getProject(), BeansCorePlugin.PLUGIN_ID) .getBoolean(BeansCorePlugin.PROJECT_PROPERTY_ID, false); } static class Version implements Comparable<Version> { private static final String MINIMUM_VERSION_STRING = "0"; public static final Version MINIMUM_VERSION = new Version(MINIMUM_VERSION_STRING); private final org.osgi.framework.Version version; public Version(String v) { org.osgi.framework.Version tempVersion = null; try { tempVersion = org.osgi.framework.Version.parseVersion(v); } catch (Exception e) { // make sure that we don't crash on any new version numbers format that we don't support BeansCorePlugin.log("Cannot convert schema vesion", e); tempVersion = org.osgi.framework.Version.parseVersion(MINIMUM_VERSION_STRING); } this.version = tempVersion; } public int compareTo(Version v2) { return this.version.compareTo(v2.version); } } }