repo-reorg-2020: moved sts4-relevant spring-ide bundles from https://github.com/spring-projects/spring-ide/releases/tag/REPO-REORG-2020 into sts4 repo
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.springframework.ide.eclipse.xml.namespaces</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,7 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
||||
@@ -0,0 +1,43 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: org.springframework.ide.eclipse.xml.namespaces
|
||||
Bundle-SymbolicName: org.springframework.ide.eclipse.xml.namespaces;singleton:=true
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Import-Package: org.eclipse.core.commands.common,
|
||||
org.eclipse.core.resources,
|
||||
org.eclipse.core.runtime,
|
||||
org.eclipse.core.runtime.jobs,
|
||||
org.eclipse.core.runtime.preferences,
|
||||
org.eclipse.jdt.core,
|
||||
org.eclipse.jdt.internal.core,
|
||||
org.eclipse.jface.action,
|
||||
org.eclipse.jface.dialogs,
|
||||
org.eclipse.jface.preference,
|
||||
org.eclipse.jface.resource,
|
||||
org.eclipse.jface.viewers,
|
||||
org.eclipse.swt,
|
||||
org.eclipse.swt.events,
|
||||
org.eclipse.swt.graphics,
|
||||
org.eclipse.swt.layout,
|
||||
org.eclipse.swt.widgets,
|
||||
org.eclipse.ui.plugin,
|
||||
org.eclipse.wst.common.uriresolver.internal.provisional,
|
||||
org.osgi.framework,
|
||||
org.osgi.service.prefs,
|
||||
org.osgi.service.url,
|
||||
org.springsource.ide.eclipse.commons.core,
|
||||
org.springsource.ide.eclipse.commons.core.util,
|
||||
org.springsource.ide.eclipse.commons.frameworks.core.util,
|
||||
org.springsource.ide.eclipse.commons.ui
|
||||
Bundle-Activator: org.springframework.ide.eclipse.xml.namespaces.SpringXmlNamespacesPlugin
|
||||
Bundle-Version: 4.8.1.qualifier
|
||||
Export-Package: org.springframework.ide.eclipse.xml.namespaces,
|
||||
org.springframework.ide.eclipse.xml.namespaces.classpath,
|
||||
org.springframework.ide.eclipse.xml.namespaces.internal,
|
||||
org.springframework.ide.eclipse.xml.namespaces.model,
|
||||
org.springframework.ide.eclipse.xml.namespaces.ui,
|
||||
org.springframework.ide.eclipse.xml.namespaces.util
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: com.google.guava,
|
||||
io.projectreactor.reactor-core;bundle-version="3.1.9",
|
||||
org.reactivestreams.reactive-streams;bundle-version="1.0.2"
|
||||
@@ -0,0 +1,17 @@
|
||||
===========================================================
|
||||
Moving namespaces extension point?
|
||||
|
||||
- id: org.springframework.ide.eclipse.beans.ui.namespaces
|
||||
|
||||
Results from extension point search:
|
||||
|
||||
org.springframework.ide.eclipse.beans.ui.namespaces - org.springframework.ide.eclipse.batch
|
||||
org.springframework.ide.eclipse.beans.ui.namespaces - org.springframework.ide.eclipse.beans.ui
|
||||
org.springframework.ide.eclipse.beans.ui.namespaces - org.springframework.ide.eclipse.data.core
|
||||
org.springframework.ide.eclipse.beans.ui.namespaces - org.springframework.ide.eclipse.integration
|
||||
org.springframework.ide.eclipse.beans.ui.namespaces - org.springframework.ide.eclipse.security
|
||||
org.springframework.ide.eclipse.beans.ui.namespaces - org.springframework.ide.eclipse.webflow.ui
|
||||
|
||||
If we move extension point to xml.namespaces plugin, the id will change
|
||||
and each of the references has to be changed.
|
||||
=============================================================
|
||||
@@ -0,0 +1,248 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
<title>About Spring IDE</title>
|
||||
<meta name="author" content="Spring IDE Developers">
|
||||
</head>
|
||||
<body>
|
||||
<h2>About Spring IDE</h2>
|
||||
<p>March 26, 2007</p>
|
||||
<h3>Abstract</h3>
|
||||
<p>Spring IDE is a set of plugins which provide a user interface for
|
||||
<a href="https://www.springframework.org">The Spring Framework</a>'s bean
|
||||
factory XML configuration files including support for Spring 2.0
|
||||
namespaces, AOP configuration and Spring Web Flow.</p>
|
||||
<h3>License</h3>
|
||||
|
||||
<p>The Spring IDE Project makes available all content in this
|
||||
plug-in ("Content"). Unless otherwise indicated below, the
|
||||
Content is provided to you under the terms and conditions of the Eclipse
|
||||
Public License Version 1.0 ("EPL"). A copy of the EPL is
|
||||
available at <a href="https://www.eclipse.org/legal/epl-v10.html">https://www.eclipse.org/legal/epl-v10.html</a>.
|
||||
For purposes of the EPL, "Program" will mean the Content.</p>
|
||||
|
||||
<p>If you did not receive this Content directly from the Spring IDE
|
||||
Project, the Content is being redistributed by another party
|
||||
("Redistributor") and different terms and conditions may apply
|
||||
to your use of any object code in the Content. Check the Redistributor's
|
||||
license that was provided with the Content. If no such license exists,
|
||||
contact the Redistributor. Unless otherwise indicated below, the terms
|
||||
and conditions of the EPL still apply to any source code in the Content
|
||||
and such source code may be obtained at <a href="https://www.eclipse.org">https://www.eclipse.org</a>.</p>
|
||||
|
||||
<h3>Third Party Content</h3>
|
||||
<p>The Content includes items that have been sourced from third
|
||||
parties as set out below. If you did not receive this Content directly
|
||||
from the Spring IDE Project, the following is provided for informational
|
||||
purposes only, and you should look to the Redistributor's license for
|
||||
terms and conditions of use.</p>
|
||||
<p><em> <strong>The Spring Framework v3.0.5</strong>
|
||||
<p>This product includes software developed by the Spring Framework
|
||||
Project (<a href="https://www.springframework.org">https://www.springframework.org</a>).</p>
|
||||
|
||||
<p><em> <strong>Spring Web Flow v2.0.7.A</strong>
|
||||
<p>This product includes software developed by the Spring Framework
|
||||
Project (<a href="https://www.springframework.org">https://www.springframework.org</a>).</p>
|
||||
|
||||
<p><em> <strong>Spring Web Services v1.5.8</strong>
|
||||
<p>This product includes software developed by the Spring Framework
|
||||
Project (<a href="https://www.springframework.org">https://www.springframework.org</a>).</p>
|
||||
|
||||
<p><em> <strong>Spring Security v3.0.2</strong>
|
||||
<p>This product includes software developed by the Spring Framework
|
||||
Project (<a href="https://www.springframework.org">https://www.springframework.org</a>).</p>
|
||||
|
||||
<p><em> <strong>Spring Dynamic Modules for OSGi(TM) Runtimes v2.0.0.M2</strong>
|
||||
<p>This product includes software developed by the Spring Framework
|
||||
Project (<a href="https://www.springframework.org">https://www.springframework.org</a>).</p>
|
||||
|
||||
<p><em> <strong>Spring Batch v2.1.0</strong>
|
||||
<p>This product includes software developed by the Spring Framework
|
||||
Project (<a href="https://www.springframework.org">https://www.springframework.org</a>).</p>
|
||||
|
||||
<p><em> <strong>Commons Codec v1.3.0</strong>
|
||||
<p>This product includes software developed by The Apache Software
|
||||
Foundation (<a href="https://www.apache.org/">https://www.apache.org/</a>).</p>
|
||||
|
||||
<p><em> <strong>Commons Collections v3.2.0</strong>
|
||||
<p>This product includes software developed by The Apache Software
|
||||
Foundation (<a href="https://www.apache.org/">https://www.apache.org/</a>).</p>
|
||||
|
||||
<p><em> <strong>Commons Logging v1.1.1</strong>
|
||||
<p>This product includes software developed by The Apache Software
|
||||
Foundation (<a href="https://www.apache.org/">https://www.apache.org/</a>).</p>
|
||||
|
||||
<p><em> <strong>Apache MyFaces v1.2.2</strong>
|
||||
<p>This product includes software developed by The Apache Software
|
||||
Foundation (<a href="https://www.apache.org/">https://www.apache.org/</a>).</p>
|
||||
|
||||
<p><em> <strong>AspectJ Weaver v1.6.10</strong>
|
||||
<p>This product includes software developed by The Eclipse Software
|
||||
Foundation (<a href="https://www.eclipse.org/">https://www.eclipse.org/</a>).</p>
|
||||
|
||||
<p><em> <strong>Antlr v3.0.1</strong>
|
||||
<p>Spring IDE includes a binary version of Antlr v3.0.1 (<a
|
||||
href="https://www.antlr.org">https://www.antlr.org/</a>).
|
||||
The source code for Antlr is available from the Antlr download site at
|
||||
<a href="https://www.antlr.org/download.html">https://www.antlr.org/download.html</a>.
|
||||
|
||||
<p>The Antlr license is available at <a
|
||||
href="https://www.antlr.org/license.html">https://www.antlr.org/license.html</a>.
|
||||
The license is also reproduced here:</p>
|
||||
|
||||
<pre>Copyright (c) 2003-2007, Terence Parr
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions
|
||||
and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
Neither the name of the author nor the names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p><em> <strong>ASM v2.2.3</strong>
|
||||
<p>Spring IDE includes a binary version of ASM v2.2.3 (<a
|
||||
href="https://asm.objectweb.org/index.html">https://asm.objectweb.org/</a>).
|
||||
The source code for ASM is available from the ObjectWeb download site at
|
||||
<a href="https://asm.objectweb.org/download/">https://asm.objectweb.org/download/</a>.
|
||||
|
||||
<p>The ASM license is available at <a
|
||||
href="https://asm.objectweb.org/license.html">https://asm.objectweb.org/license.html</a>.
|
||||
The license is also reproduced here:</p>
|
||||
|
||||
<pre>Copyright (c) 2000-2005 INRIA, France Telecom
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holders nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</pre></p>
|
||||
|
||||
|
||||
<p><em> <strong>backport-util-concurrent 3.1.0</strong>
|
||||
<p>Spring IDE includes a binary version of backport-util-concurrent v3.1.0 (<a
|
||||
href="https://dcl.mathcs.emory.edu/util/backport-util-concurrent/">https://dcl.mathcs.emory.edu/util/backport-util-concurrent/</a>).
|
||||
The source code for backport-util-concurrent is available from the download site at
|
||||
<a href="https://dcl.mathcs.emory.edu/util/backport-util-concurrent/dist/">https://dcl.mathcs.emory.edu/util/backport-util-concurrent/dist/</a>.
|
||||
|
||||
|
||||
<p>The backport-util-concurrent license is available at <a
|
||||
href="https://creativecommons.org/licenses/publicdomain">https://creativecommons.org/licenses/publicdomain</a>.
|
||||
The license is also reproduced here:</p>
|
||||
|
||||
<pre><em>Copyright-Only Dedication (based on United States law) or Public Domain Certification</em>
|
||||
|
||||
The person or persons who have associated work with this document (the
|
||||
"Dedicator" or "Certifier") hereby either (a) certifies that, to the
|
||||
best of his knowledge, the work of authorship identified is in the public
|
||||
domain of the country from which the work is published, or (b) hereby
|
||||
dedicates whatever copyright the dedicators holds in the work of authorship
|
||||
identified below (the "Work") to the public domain. A certifier, moreover,
|
||||
dedicates any copyright interest he may have in the associated work, and
|
||||
for these purposes, is described as a "dedicator" below.
|
||||
|
||||
A certifier has taken reasonable steps to verify the copyright status of
|
||||
this work. Certifier recognizes that his good faith efforts may not shield
|
||||
him from liability if in fact the work certified is not in the public domain.
|
||||
|
||||
Dedicator makes this dedication for the benefit of the public at large and
|
||||
to the detriment of the Dedicator's heirs and successors. Dedicator intends
|
||||
this dedication to be an overt act of relinquishment in perpetuity of all
|
||||
present and future rights under copyright law, whether vested or contingent,
|
||||
in the Work. Dedicator understands that such relinquishment of all rights
|
||||
includes the relinquishment of all rights to enforce (by lawsuit or otherwise)
|
||||
those copyrights in the Work.
|
||||
|
||||
Dedicator recognizes that, once placed in the public domain, the Work may be
|
||||
freely reproduced, distributed, transmitted, used, modified, built upon, or
|
||||
otherwise exploited by anyone for any purpose, commercial or non-commercial,
|
||||
and in any way, including by methods that have not yet been invented or
|
||||
conceived.
|
||||
</pre></p>
|
||||
|
||||
<p><em> <strong>AOP Alliance</strong>
|
||||
<p>LICENCE: all the source code provided by AOP Alliance is Public Domain.
|
||||
</p>
|
||||
|
||||
<p><em> <strong>javax.el v1.0.0</strong>
|
||||
<p>This product includes software distributed by Sun (meanwhile Oracle) under CDDL license
|
||||
(<a href="https://www.sun.com/cddl/cddl.html">https://www.sun.com/cddl/cddl.html</a>).</p>
|
||||
|
||||
<p><em> <strong>javax.jms v1.1.0</strong>
|
||||
<p>This product includes software distributed by Sun (meanwhile Oracle) under CDDL license
|
||||
(<a href="https://www.sun.com/cddl/cddl.html">https://www.sun.com/cddl/cddl.html</a>).</p>
|
||||
|
||||
<p><em> <strong>javax.servlet v2.5.0</strong>
|
||||
<p>This product includes software distributed by Sun (meanwhile Oracle) under CDDL license
|
||||
(<a href="https://www.sun.com/cddl/cddl.html">https://www.sun.com/cddl/cddl.html</a>).</p>
|
||||
|
||||
<p><em> <strong>javax.servlet.jsp v2.1.0</strong>
|
||||
<p>This product includes software distributed by Sun (meanwhile Oracle) under CDDL license
|
||||
(<a href="https://www.sun.com/cddl/cddl.html">https://www.sun.com/cddl/cddl.html</a>).</p>
|
||||
|
||||
<p><em> <strong>javax.servlet.jsp.jstl v1.2.0</strong>
|
||||
<p>This product includes software distributed by Sun (meanwhile Oracle) under CDDL license
|
||||
(<a href="https://www.sun.com/cddl/cddl.html">https://www.sun.com/cddl/cddl.html</a>).</p>
|
||||
|
||||
<p><em> <strong>javax.activation v1.1.0</strong>
|
||||
<p>This product includes software distributed by Sun (meanwhile Oracle) under CDDL license
|
||||
(<a href="https://www.sun.com/cddl/cddl.html">https://www.sun.com/cddl/cddl.html</a>).</p>
|
||||
|
||||
<p><em> <strong>javax.annotation v1.0.0</strong>
|
||||
<p>This product includes software distributed by Sun (meanwhile Oracle) under CDDL license
|
||||
(<a href="https://www.sun.com/cddl/cddl.html">https://www.sun.com/cddl/cddl.html</a>).</p>
|
||||
|
||||
<p><em> <strong>javax.mail v1.4.0</strong>
|
||||
<p>This product includes software distributed by Sun (meanwhile Oracle) under CDDL license
|
||||
(<a href="https://www.sun.com/cddl/cddl.html">https://www.sun.com/cddl/cddl.html</a>).</p>
|
||||
|
||||
<p><em> <strong>javax.xml.stream v1.0.1</strong>
|
||||
<p>This product includes software distributed by Sun (meanwhile Oracle) under CDDL license
|
||||
(<a href="https://www.sun.com/cddl/cddl.html">https://www.sun.com/cddl/cddl.html</a>).</p>
|
||||
|
||||
<p><em> <strong>javax.xml.ws v2.1.0</strong>
|
||||
<p>This product includes software distributed by Sun (meanwhile Oracle) under CDDL license
|
||||
(<a href="https://www.sun.com/cddl/cddl.html">https://www.sun.com/cddl/cddl.html</a>).</p>
|
||||
|
||||
</em></p>
|
||||
|
||||
|
||||
<address>Copyright (c) 2005, 2011 Spring IDE Developers</address>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.,\
|
||||
plugin.xml,\
|
||||
icons/,\
|
||||
about.html,\
|
||||
schema/
|
||||
src.includes = about.html
|
||||
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 155 B |
|
After Width: | Height: | Size: 219 B |
|
After Width: | Height: | Size: 149 B |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 100 B |
|
After Width: | Height: | Size: 153 B |
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 578 B |
|
After Width: | Height: | Size: 160 B |
|
After Width: | Height: | Size: 598 B |
|
After Width: | Height: | Size: 955 B |
|
After Width: | Height: | Size: 126 B |
|
After Width: | Height: | Size: 564 B |
|
After Width: | Height: | Size: 580 B |
|
After Width: | Height: | Size: 127 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 552 B |
|
After Width: | Height: | Size: 333 B |
|
After Width: | Height: | Size: 544 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 603 B |
|
After Width: | Height: | Size: 606 B |
|
After Width: | Height: | Size: 555 B |
|
After Width: | Height: | Size: 141 B |
|
After Width: | Height: | Size: 624 B |
|
After Width: | Height: | Size: 310 B |
|
After Width: | Height: | Size: 555 B |
|
After Width: | Height: | Size: 555 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 583 B |
|
After Width: | Height: | Size: 569 B |
|
After Width: | Height: | Size: 534 B |
|
After Width: | Height: | Size: 604 B |
|
After Width: | Height: | Size: 85 B |
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 577 B |
|
After Width: | Height: | Size: 1015 B |
|
After Width: | Height: | Size: 339 B |
|
After Width: | Height: | Size: 345 B |
|
After Width: | Height: | Size: 917 B |
|
After Width: | Height: | Size: 577 B |
|
After Width: | Height: | Size: 323 B |
|
After Width: | Height: | Size: 553 B |
|
After Width: | Height: | Size: 606 B |
|
After Width: | Height: | Size: 317 B |
|
After Width: | Height: | Size: 533 B |
|
After Width: | Height: | Size: 542 B |
|
After Width: | Height: | Size: 335 B |
|
After Width: | Height: | Size: 590 B |
|
After Width: | Height: | Size: 617 B |
|
After Width: | Height: | Size: 904 B |
|
After Width: | Height: | Size: 568 B |
|
After Width: | Height: | Size: 551 B |
|
After Width: | Height: | Size: 592 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 592 B |
|
After Width: | Height: | Size: 581 B |
|
After Width: | Height: | Size: 129 B |
|
After Width: | Height: | Size: 564 B |
|
After Width: | Height: | Size: 587 B |
|
After Width: | Height: | Size: 574 B |
|
After Width: | Height: | Size: 79 B |
|
After Width: | Height: | Size: 62 B |
|
After Width: | Height: | Size: 81 B |
|
After Width: | Height: | Size: 82 B |
|
After Width: | Height: | Size: 79 B |
|
After Width: | Height: | Size: 104 B |
|
After Width: | Height: | Size: 79 B |
|
After Width: | Height: | Size: 826 B |
|
After Width: | Height: | Size: 173 B |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?eclipse version="3.4"?>
|
||||
<plugin>
|
||||
<extension-point id="namespacemanager" name="namespacemanager" schema="schema/namespacemanager.exsd"/>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.wst.common.uriresolver.resolverExtensions">
|
||||
<resolverExtension
|
||||
class="org.springframework.ide.eclipse.xml.namespaces.internal.ProjectClasspathExtensibleUriResolver"
|
||||
priority="high"
|
||||
stage="postnormalization">
|
||||
<!-- <projectNature
|
||||
value="org.springframework.ide.eclipse.core.springnature">
|
||||
</projectNature> -->
|
||||
</resolverExtension>
|
||||
</extension>
|
||||
|
||||
<extension
|
||||
point="org.eclipse.ui.propertyPages">
|
||||
<page
|
||||
id="org.springframework.ide.eclipse.beans.ui.namespaces.projectPropertyPage"
|
||||
name="Namespaces"
|
||||
class="org.springframework.ide.eclipse.xml.namespaces.ui.preferences.NamespaceVersionPreferencePage"
|
||||
adaptable="true"
|
||||
objectClass="org.eclipse.core.resources.IProject"
|
||||
category="org.springframework.ide.eclipse.beans.ui.properties.ProjectPropertyPage">
|
||||
<!-- <filter
|
||||
name="nature"
|
||||
value="org.springframework.ide.eclipse.core.springnature">
|
||||
</filter> -->
|
||||
<keywordReference
|
||||
id="org.springframework.ide.eclipse.beans.ui.namespaces.keywords">
|
||||
</keywordReference>
|
||||
</page>
|
||||
</extension>
|
||||
<extension point="org.eclipse.ui.keywords">
|
||||
<keyword id="org.springframework.ide.eclipse.beans.ui.namespaces.keywords"
|
||||
label="Spring Beans config xsd schema location version"/>
|
||||
</extension>
|
||||
|
||||
<extension point="org.eclipse.ui.preferencePages">
|
||||
<page id="org.springframework.ide.eclipse.beans.ui.namespaces.preferencePage"
|
||||
name="Namespaces"
|
||||
class="org.springframework.ide.eclipse.xml.namespaces.ui.preferences.NamespaceVersionPreferencePage"
|
||||
category="org.springsource.ide.eclipse.commons.preferencePage">
|
||||
</page>
|
||||
</extension>
|
||||
|
||||
</plugin>
|
||||
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot.ide</groupId>
|
||||
<artifactId>org.springframework.boot.ide</artifactId>
|
||||
<version>4.8.1-SNAPSHOT</version>
|
||||
<relativePath>../../eclipse-distribution/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>org.springframework.ide.eclipse</groupId>
|
||||
<artifactId>org.springframework.ide.eclipse.xml.namespaces</artifactId>
|
||||
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>target-platform-configuration</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<resolver>p2</resolver>
|
||||
<pomDependencies>ignore</pomDependencies>
|
||||
<dependency-resolution>
|
||||
<extraRequirements>
|
||||
<requirement>
|
||||
<type>eclipse-plugin</type>
|
||||
<id>org.eclipse.jface.text</id>
|
||||
<versionRange>0.0.0</versionRange>
|
||||
</requirement>
|
||||
<requirement>
|
||||
<type>eclipse-plugin</type>
|
||||
<id>org.eclipse.ui.ide</id>
|
||||
<versionRange>0.0.0</versionRange>
|
||||
</requirement>
|
||||
</extraRequirements>
|
||||
</dependency-resolution>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-source-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>plugin-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>plugin-source</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-p2-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>second-generate-p2-metadata</id>
|
||||
<goals>
|
||||
<goal>p2-metadata</goal>
|
||||
</goals>
|
||||
<phase>verify</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,102 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!-- Schema file written by PDE -->
|
||||
<schema targetNamespace="org.springframework.ide.eclipse.xml.namespaces" xmlns="http://www.w3.org/2001/XMLSchema">
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.schema plugin="org.springframework.ide.eclipse.xml.namespaces" id="namespacemanager" name="namespacemanager"/>
|
||||
</appinfo>
|
||||
<documentation>
|
||||
[Enter description of this extension point.]
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
<element name="extension">
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.element />
|
||||
</appinfo>
|
||||
</annotation>
|
||||
<complexType>
|
||||
<sequence>
|
||||
<element ref="namespacemanager"/>
|
||||
</sequence>
|
||||
<attribute name="point" type="string" use="required">
|
||||
<annotation>
|
||||
<documentation>
|
||||
|
||||
</documentation>
|
||||
</annotation>
|
||||
</attribute>
|
||||
<attribute name="id" type="string">
|
||||
<annotation>
|
||||
<documentation>
|
||||
|
||||
</documentation>
|
||||
</annotation>
|
||||
</attribute>
|
||||
<attribute name="name" type="string">
|
||||
<annotation>
|
||||
<documentation>
|
||||
|
||||
</documentation>
|
||||
<appinfo>
|
||||
<meta.attribute translatable="true"/>
|
||||
</appinfo>
|
||||
</annotation>
|
||||
</attribute>
|
||||
</complexType>
|
||||
</element>
|
||||
|
||||
<element name="namespacemanager">
|
||||
<complexType>
|
||||
<attribute name="class" type="string" use="required">
|
||||
<annotation>
|
||||
<documentation>
|
||||
|
||||
</documentation>
|
||||
<appinfo>
|
||||
<meta.attribute kind="java" basedOn=":org.springframework.ide.eclipse.xml.namespaces.INamespaceManager"/>
|
||||
</appinfo>
|
||||
</annotation>
|
||||
</attribute>
|
||||
</complexType>
|
||||
</element>
|
||||
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.section type="since"/>
|
||||
</appinfo>
|
||||
<documentation>
|
||||
[Enter the first release in which this extension point appears.]
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.section type="examples"/>
|
||||
</appinfo>
|
||||
<documentation>
|
||||
[Enter extension point usage example here.]
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.section type="apiinfo"/>
|
||||
</appinfo>
|
||||
<documentation>
|
||||
[Enter API information here.]
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
<annotation>
|
||||
<appinfo>
|
||||
<meta.section type="implementation"/>
|
||||
</appinfo>
|
||||
<documentation>
|
||||
[Enter information about supplied implementation of this extension point.]
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
|
||||
</schema>
|
||||
@@ -0,0 +1,27 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.INamespaceDefinitionListener;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.INamespaceDefinitionResolver;
|
||||
|
||||
public interface INamespaceManager {
|
||||
|
||||
void unregisterNamespaceDefinitionListener(INamespaceDefinitionListener listener);
|
||||
void registerNamespaceDefinitionListener(INamespaceDefinitionListener listener);
|
||||
void notifyNamespaceDefinitionListeners(IProject project);
|
||||
|
||||
INamespaceDefinitionResolver getNamespaceDefinitionResolver();
|
||||
CompletableFuture<?> nameSpaceHandlersReady();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.eclipse.core.runtime.IConfigurationElement;
|
||||
import org.eclipse.core.runtime.IExtension;
|
||||
import org.eclipse.core.runtime.IExtensionPoint;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.INamespaceDefinition;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.INamespaceDefinitionListener;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.INamespaceDefinitionResolver;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Provides {@link INamespaceManager} instance loaded from
|
||||
* extension point.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class NamespaceManagerProvider {
|
||||
|
||||
private static String EXTENSION_POINT = SpringXmlNamespacesPlugin.PLUGIN_ID+".namespacemanager";
|
||||
|
||||
/**
|
||||
* Dummy implementation to use when there is no contributed {@link INamespaceManager}
|
||||
*/
|
||||
private static INamespaceManager NULL = new INamespaceManager() {
|
||||
|
||||
@Override
|
||||
public void unregisterNamespaceDefinitionListener(INamespaceDefinitionListener listener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerNamespaceDefinitionListener(INamespaceDefinitionListener listener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNamespaceDefinitionListeners(IProject project) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public INamespaceDefinitionResolver getNamespaceDefinitionResolver() {
|
||||
return new INamespaceDefinitionResolver() {
|
||||
|
||||
@Override
|
||||
public INamespaceDefinition resolveNamespaceDefinition(String namespaceUri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<INamespaceDefinition> getNamespaceDefinitions() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<?> nameSpaceHandlersReady() {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
};
|
||||
|
||||
private static INamespaceManager instance;
|
||||
|
||||
public static synchronized INamespaceManager get() {
|
||||
if (instance==null) {
|
||||
instance = create();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static INamespaceManager create() {
|
||||
try {
|
||||
IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(EXTENSION_POINT);
|
||||
if (point!=null) {
|
||||
IExtension[] extensions = point.getExtensions();
|
||||
if (extensions!=null && extensions.length>0) {
|
||||
Assert.isLegal(extensions.length==1);
|
||||
IConfigurationElement[] configs = extensions[0].getConfigurationElements();
|
||||
if (configs!=null) {
|
||||
Assert.isLegal(configs.length==1);
|
||||
return (INamespaceManager) configs[0].createExecutableExtension("class");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SpringXmlNamespacesPlugin.log(e);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 Pivotal Software Inc.
|
||||
* 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Spring IDE Developers - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.osgi.service.url.AbstractURLStreamHandlerService;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.classpath.ProjectResourceLoaderCache;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.classpath.ResourceLoader;
|
||||
import org.springsource.ide.eclipse.commons.core.JdtUtils;
|
||||
|
||||
/**
|
||||
* Support for "project-aware" URL protocol. The protocol is for resources
|
||||
* within JARs. The JARs are located within a Spring project.
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
public class ProjectAwareUrlStreamHandlerService extends
|
||||
AbstractURLStreamHandlerService {
|
||||
|
||||
public static final String PROJECT_AWARE_PROTOCOL = "project-aware";
|
||||
public static final String PROJECT_AWARE_PROTOCOL_HEADER = PROJECT_AWARE_PROTOCOL + "://";
|
||||
|
||||
@Override
|
||||
public URLConnection openConnection(URL u) throws IOException {
|
||||
String systemId = u.toString();
|
||||
String nameAndLocation = systemId.substring(PROJECT_AWARE_PROTOCOL_HEADER.length());
|
||||
String projectName = nameAndLocation.substring(0, nameAndLocation.indexOf('/'));
|
||||
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
|
||||
String resourceId = nameAndLocation.substring(nameAndLocation.indexOf('/') + 1);
|
||||
ResourceLoader cl = ProjectResourceLoaderCache.getResourceLoader(project, null);
|
||||
URL resource = cl.getResource(resourceId);
|
||||
if (resource != null) {
|
||||
return resource.openConnection();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string representation of a project-aware protocol URL from
|
||||
* project name and a resource name
|
||||
*
|
||||
* @param projectName
|
||||
* spring project name
|
||||
* @param resourceName
|
||||
* class loader resource name
|
||||
* @return URL string
|
||||
*/
|
||||
public static String createProjectAwareUrl(String projectName, String resourceName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(ProjectAwareUrlStreamHandlerService.PROJECT_AWARE_PROTOCOL_HEADER);
|
||||
sb.append(projectName);
|
||||
sb.append('/');
|
||||
sb.append(resourceName);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2004, 2015 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Spring IDE Developers - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.jface.resource.ImageRegistry;
|
||||
import org.eclipse.ui.plugin.AbstractUIPlugin;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.service.url.URLConstants;
|
||||
import org.osgi.service.url.URLStreamHandlerService;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.internal.ProjectClasspathNamespaceDefinitionResolverCache;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.INamespaceDefinitionResolver;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.ui.XmlNamespacesUIImages;
|
||||
|
||||
/**
|
||||
* Central access point for the Spring Framework Core plug-in (id
|
||||
* <code>"org.springframework.ide.eclipse.beans.core"</code>).
|
||||
*
|
||||
* @author Torsten Juergeleit
|
||||
* @author Christian Dupuis
|
||||
* @author Tomasz Zarna
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class SpringXmlNamespacesPlugin extends AbstractUIPlugin {
|
||||
|
||||
/**
|
||||
* Plugin identifier for Spring Beans Core (value <code>org.springframework.ide.eclipse.beans.core</code>).
|
||||
*/
|
||||
public static final String PLUGIN_ID = "org.springframework.ide.eclipse.xml.namespaces";
|
||||
|
||||
/** preference key to load namespace handler by searching source folders */
|
||||
public static final String DISABLE_CACHING_FOR_NAMESPACE_LOADING_ID = "disableCachingForNamespaceLoadingFromClasspath";
|
||||
|
||||
/** preference key to load namespace handler from classpath */
|
||||
public static final String LOAD_NAMESPACEHANDLER_FROM_CLASSPATH_ID = "loadNamespaceHandlerFromClasspath";
|
||||
|
||||
/** preference key to specify the default namespace version */
|
||||
public static final String NAMESPACE_DEFAULT_VERSION_PREFERENCE_ID = "default.version.";
|
||||
|
||||
/** preference key to specify if versions should be taken from the classpath */
|
||||
public static final String NAMESPACE_DEFAULT_FROM_CLASSPATH_ID = "default.version.check.classpath";
|
||||
|
||||
/** preference key to specify the default namespace version */
|
||||
public static final String NAMESPACE_PREFIX_PREFERENCE_ID = "prefix.";
|
||||
|
||||
/** preference key to specify whether wizards automatically convert all newly inserted namespace
|
||||
* locations into https */
|
||||
public static final String USE_HTTPS_FOR_SCHEMA_LOCATIONS = "use.https.for.new.namespace.locations";
|
||||
|
||||
/** preference key to enable namespace versions per namespace */
|
||||
public static final String PROJECT_PROPERTY_ID = "enable.project.preferences";
|
||||
|
||||
/** preference key to suppress missing namespace handler warnings */
|
||||
public static final String IGNORE_MISSING_NAMESPACEHANDLER_PROPERTY = "ignoreMissingNamespaceHandler";
|
||||
|
||||
public static final boolean IGNORE_MISSING_NAMESPACEHANDLER_PROPERTY_DEFAULT = false;
|
||||
|
||||
|
||||
/** The shared instance */
|
||||
private static SpringXmlNamespacesPlugin plugin;
|
||||
|
||||
/**
|
||||
* Creates the Spring Beans Core plug-in.
|
||||
* <p>
|
||||
* The plug-in instance is created automatically by the Eclipse platform. Clients must not call.
|
||||
*/
|
||||
public SpringXmlNamespacesPlugin() {
|
||||
plugin = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitor used for dealing with the bundle activator and synchronous bundle threads
|
||||
*/
|
||||
private transient final Object monitor = new Object();
|
||||
|
||||
/**
|
||||
* flag indicating whether the context is down or not - useful during shutdown
|
||||
*/
|
||||
private volatile boolean isClosed = false;
|
||||
|
||||
private ServiceRegistration<?> projectAwareUrlService = null;
|
||||
|
||||
@Override
|
||||
protected void initializeImageRegistry(ImageRegistry registry) {
|
||||
XmlNamespacesUIImages.initializeImageRegistry(registry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(final BundleContext context) throws Exception {
|
||||
super.start(context);
|
||||
|
||||
Hashtable<String, String> properties = new Hashtable<String, String>();
|
||||
properties.put(URLConstants.URL_HANDLER_PROTOCOL,
|
||||
ProjectAwareUrlStreamHandlerService.PROJECT_AWARE_PROTOCOL);
|
||||
projectAwareUrlService = context.registerService(
|
||||
URLStreamHandlerService.class.getName(),
|
||||
new ProjectAwareUrlStreamHandlerService(), properties);
|
||||
|
||||
// executorService = Executors.newCachedThreadPool(new ThreadFactory() {
|
||||
//
|
||||
// public Thread newThread(Runnable runnable) {
|
||||
// Version version = Version.parseVersion(getPluginVersion());
|
||||
// String productId = "Spring IDE";
|
||||
// IProduct product = Platform.getProduct();
|
||||
// if (product != null && "com.springsource.sts".equals(product.getId()))
|
||||
// productId = "STS";
|
||||
// Thread reportingThread = new Thread(runnable, String.format(THREAD_NAME_TEMPLATE, threadCount.incrementAndGet(),
|
||||
// productId, version.getMajor(), version.getMinor(), version.getMicro()));
|
||||
// reportingThread.setDaemon(true);
|
||||
// return reportingThread;
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
// getPreferenceStore().setDefault(TIMEOUT_CONFIG_LOADING_PREFERENCE_ID, 60);
|
||||
getPreferenceStore().setDefault(NAMESPACE_DEFAULT_FROM_CLASSPATH_ID, true);
|
||||
getPreferenceStore().setDefault(LOAD_NAMESPACEHANDLER_FROM_CLASSPATH_ID, true);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
synchronized (monitor) {
|
||||
// if already closed, bail out
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
isClosed = true;
|
||||
}
|
||||
// model.stop();
|
||||
if (projectAwareUrlService != null) {
|
||||
projectAwareUrlService.unregister();
|
||||
}
|
||||
super.stop(context);
|
||||
}
|
||||
|
||||
public static boolean isDebug(String option) {
|
||||
String value = Platform.getDebugOption(option);
|
||||
return (value != null && value.equalsIgnoreCase("true") ? true : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared instance.
|
||||
*/
|
||||
public static SpringXmlNamespacesPlugin getDefault() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the message to the plug-in's log
|
||||
*
|
||||
* @param message the text to write to the log
|
||||
*/
|
||||
public static void log(String message, Throwable exception) {
|
||||
IStatus status = createErrorStatus(message, exception);
|
||||
getDefault().getLog().log(status);
|
||||
}
|
||||
|
||||
public static void log(Throwable exception) {
|
||||
getDefault().getLog().log(createErrorStatus("Plugin.internal_error", exception));
|
||||
}
|
||||
|
||||
public static IStatus createErrorStatus(String message, Throwable exception) {
|
||||
return createStatus(IStatus.ERROR, message, exception);
|
||||
}
|
||||
|
||||
public static IStatus createStatus(int severity, String message, Throwable exception) {
|
||||
return new Status(severity, PLUGIN_ID, 0, message == null ? "" : message, exception);
|
||||
}
|
||||
|
||||
public static void logAsWarning(Throwable exception) {
|
||||
getDefault().getLog().log(createWarningStatus("Plugin.internal_warning", exception));
|
||||
}
|
||||
|
||||
public static IStatus createWarningStatus(String message, Throwable exception) {
|
||||
return createStatus(IStatus.WARNING, message, exception);
|
||||
}
|
||||
|
||||
public static INamespaceDefinitionResolver getNamespaceDefinitionResolver(IProject project) {
|
||||
if (project != null) {
|
||||
return ProjectClasspathNamespaceDefinitionResolverCache.getResolver(project);
|
||||
}
|
||||
return getNamespaceDefinitionResolver();
|
||||
}
|
||||
|
||||
public static INamespaceDefinitionResolver getNamespaceDefinitionResolver() {
|
||||
return NamespaceManagerProvider.get().getNamespaceDefinitionResolver();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2007, 2012, 2019 Pivotal, Inc.
|
||||
* 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.springsource.ide.eclipse.commons.core.SpringCorePreferences;
|
||||
|
||||
public class XmlNamespaceUtils {
|
||||
|
||||
public static boolean convertNamespaceLocationsToHttps(IProject project) {
|
||||
if (SpringCorePreferences.getProjectPreferences(project, SpringXmlNamespacesPlugin.PLUGIN_ID).getBoolean(
|
||||
SpringXmlNamespacesPlugin.PROJECT_PROPERTY_ID, false)) {
|
||||
return SpringCorePreferences.getProjectPreferences(project, SpringXmlNamespacesPlugin.PLUGIN_ID).getBoolean(
|
||||
SpringXmlNamespacesPlugin.USE_HTTPS_FOR_SCHEMA_LOCATIONS, false);
|
||||
}
|
||||
return SpringXmlNamespacesPlugin.getDefault().getPluginPreferences().getBoolean(
|
||||
SpringXmlNamespacesPlugin.USE_HTTPS_FOR_SCHEMA_LOCATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given XSD schema location to https if the preference is enabled.
|
||||
*/
|
||||
public static String convertToHttps(IProject project, String schemaLocation) {
|
||||
if (convertNamespaceLocationsToHttps(project) && schemaLocation.startsWith("http:")) {
|
||||
return "https"+schemaLocation.substring(4);
|
||||
}
|
||||
return schemaLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a project should load namespace handlers from the classpath or use the global catalog.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean useNamespacesFromClasspath(IProject project) {
|
||||
if (project == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SpringCorePreferences.getProjectPreferences(project, SpringXmlNamespacesPlugin.PLUGIN_ID).getBoolean(
|
||||
SpringXmlNamespacesPlugin.PROJECT_PROPERTY_ID, false)) {
|
||||
return SpringCorePreferences.getProjectPreferences(project, SpringXmlNamespacesPlugin.PLUGIN_ID).getBoolean(
|
||||
SpringXmlNamespacesPlugin.LOAD_NAMESPACEHANDLER_FROM_CLASSPATH_ID, false);
|
||||
}
|
||||
return SpringXmlNamespacesPlugin.getDefault().getPluginPreferences().getBoolean(
|
||||
SpringXmlNamespacesPlugin.LOAD_NAMESPACEHANDLER_FROM_CLASSPATH_ID);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean disableCachingForNamespaceLoadingFromClasspath(IProject project) {
|
||||
if (project == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SpringCorePreferences.getProjectPreferences(project, SpringXmlNamespacesPlugin.PLUGIN_ID).getBoolean(
|
||||
SpringXmlNamespacesPlugin.PROJECT_PROPERTY_ID, false)) {
|
||||
return SpringCorePreferences.getProjectPreferences(project, SpringXmlNamespacesPlugin.PLUGIN_ID).getBoolean(
|
||||
SpringXmlNamespacesPlugin.DISABLE_CACHING_FOR_NAMESPACE_LOADING_ID, false);
|
||||
}
|
||||
return SpringXmlNamespacesPlugin.getDefault().getPluginPreferences().getBoolean(
|
||||
SpringXmlNamespacesPlugin.DISABLE_CACHING_FOR_NAMESPACE_LOADING_ID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.classpath;
|
||||
|
||||
import static org.springframework.ide.eclipse.xml.namespaces.classpath.ProjectResourceLoaderCache.shouldFilter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import org.eclipse.core.runtime.URIUtil;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.SpringXmlNamespacesPlugin;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
public class FilteringURLResourceLoader extends ResourceLoader {
|
||||
|
||||
// private static Map<String, AtomicLong> jarScanned = Collections.synchronizedMap(new HashMap<String, AtomicLong>());
|
||||
|
||||
// private static final boolean DEBUG = false;
|
||||
|
||||
private static Set<String> _fetchedResources = Collections.synchronizedSet(new HashSet<>());
|
||||
private static ImmutableSet<String> fetchedResources = ImmutableSet.copyOf(_fetchedResources);
|
||||
|
||||
private URL[] urls;
|
||||
private ResourceLoader parent;
|
||||
|
||||
private Set<String> _indexValidFor = ImmutableSet.of();
|
||||
private ImmutableSetMultimap<String, String> resourcesIndex = null;
|
||||
|
||||
|
||||
public FilteringURLResourceLoader(URL[] directories, ResourceLoader parent) {
|
||||
this.urls = directories;
|
||||
this.parent = parent == null ? ResourceLoader.NULL : parent;
|
||||
}
|
||||
|
||||
private static AtomicLong timeUsed = new AtomicLong();
|
||||
private static AtomicLong request = new AtomicLong();
|
||||
|
||||
private static AtomicLong indexBuilt = new AtomicLong();
|
||||
private static AtomicLong indexReused = new AtomicLong();
|
||||
|
||||
|
||||
|
||||
// @Override
|
||||
// public URL getResource(String resourceName) {
|
||||
// try {
|
||||
// if (!shouldFilter(resourceName)) {
|
||||
// URL fromParent = parent.getResource(resourceName);
|
||||
// if (fromParent!=null) {
|
||||
// return fromParent;
|
||||
// }
|
||||
// Collection<String> resources = getResourcesCollection(resourceName);
|
||||
// if (!resources.isEmpty()) {
|
||||
// return new URL(resources.iterator().next());
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// SpringXmlNamespacesPlugin.log(e);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* Get's collection of resources from this resource loader, but excluding resources
|
||||
* from the parent.
|
||||
*/
|
||||
private Collection<String> getResourcesCollection(String resourceName) {
|
||||
if (!shouldFilter(resourceName)) {
|
||||
// long start = System.currentTimeMillis();
|
||||
try {
|
||||
ensureIndexed(resourceName);
|
||||
Collection<String> r = resourcesIndex.get(resourceName);
|
||||
return r != null ? r : ImmutableList.of();
|
||||
} catch (Exception e) {
|
||||
SpringXmlNamespacesPlugin.log(e);
|
||||
// } finally {
|
||||
// long duration = System.currentTimeMillis() - start;
|
||||
// long total = timeUsed.addAndGet(duration);
|
||||
// long requestCount = request.incrementAndGet();
|
||||
// System.out.println("Time spent finding resources:");
|
||||
// System.out.println(" requests = " + requestCount);
|
||||
// System.out.println(" avg = " + total / requestCount);
|
||||
// System.out.println(" total = " + total);
|
||||
// System.out.println(" index built/reused = " + indexBuilt.get() +" / "+indexReused.get());
|
||||
|
||||
// System.out.println("Jar scan counts:");
|
||||
// for (Entry<String, AtomicLong> e : jarScanned.entrySet()) {
|
||||
// System.out.println(" "+e.getValue().get() +": "+e.getKey());
|
||||
// }
|
||||
}
|
||||
}
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
private synchronized void ensureIndexed(String resourceName) {
|
||||
if (resourcesIndex!=null && isIndexValidFor(resourceName)) {
|
||||
indexReused.incrementAndGet();
|
||||
} else {
|
||||
indexBuilt.incrementAndGet();
|
||||
synchronized (_fetchedResources) {
|
||||
if (_fetchedResources.add(resourceName)) {
|
||||
fetchedResources = ImmutableSet.copyOf(_fetchedResources);
|
||||
// save(_fetchedResources);
|
||||
}
|
||||
}
|
||||
resourcesIndex = buildIndex(name -> isInterestingByDefault(name) || fetchedResources.contains(name));
|
||||
_indexValidFor = fetchedResources;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isIndexValidFor(String resourceName) {
|
||||
return isInterestingByDefault(resourceName) || _indexValidFor.contains(resourceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* If you can predict, based on looking at a resourceName that it is likely to
|
||||
* be 'interesting' for future lookups, then this method can be overridden so it returns true
|
||||
* for those 'interesting' resources. This will allow the resource-loader to pre-cache
|
||||
* the interesting values from the get-go, and thereby avoid rebuilding the
|
||||
* index multiple times.
|
||||
* <p>
|
||||
* The default implementation provided here is optimised specifically for resolving
|
||||
* spring .xsd schemas.
|
||||
*/
|
||||
protected boolean isInterestingByDefault(String resourceName) {
|
||||
return resourceName.startsWith("META-INF/spring") || resourceName.endsWith(".xsd");
|
||||
}
|
||||
|
||||
private ImmutableSetMultimap<String, String> buildIndex(Predicate<String> interestingResourceNames) {
|
||||
ImmutableSetMultimap.Builder<String, String> resources = ImmutableSetMultimap.builder();
|
||||
//find in our urls
|
||||
for (URL url : urls) {
|
||||
try {
|
||||
if (isZip(url)) {
|
||||
fetchResourceFromZip(interestingResourceNames, url, resources);
|
||||
} else {
|
||||
url.getProtocol().equals("file");
|
||||
File file = URIUtil.toFile(URIUtil.toURI(url));
|
||||
if (file.isDirectory()) {
|
||||
fetchResourceFromDirectory(interestingResourceNames, file, resources);
|
||||
} else {
|
||||
fetchResourceFromZip(interestingResourceNames, url, resources);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SpringXmlNamespacesPlugin.log(e);
|
||||
}
|
||||
}
|
||||
return resources.build();
|
||||
}
|
||||
|
||||
private void fetchResourceFromDirectory(Predicate<String> interesttingResourceNames,
|
||||
File file,
|
||||
ImmutableSetMultimap.Builder<String, String> resources
|
||||
) {
|
||||
try {
|
||||
Path rootDir = file.toPath();
|
||||
FileVisitor<Path> visitor = new FileVisitor<Path>() {
|
||||
|
||||
final FileVisitResult fvr = FileVisitResult.CONTINUE;
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
return fvr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (attrs.isRegularFile()) {
|
||||
String name = rootDir.relativize(file).toString();
|
||||
if (interesttingResourceNames.test(name)) {
|
||||
resources.put(name, file.toUri().toString());
|
||||
}
|
||||
}
|
||||
return fvr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
|
||||
return fvr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
return fvr;
|
||||
}
|
||||
};
|
||||
Files.walkFileTree(rootDir, visitor);
|
||||
} catch (IOException e) {
|
||||
SpringXmlNamespacesPlugin.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchResourceFromZip(Predicate<String> interestingResourceNames, URL url, ImmutableSetMultimap.Builder<String, String> requestor) {
|
||||
// AtomicLong counter = jarScanned.computeIfAbsent(url.toString(), s -> new AtomicLong());
|
||||
// counter.incrementAndGet();
|
||||
try {
|
||||
try (InputStream input = url.openStream()) {
|
||||
ZipInputStream zip = new ZipInputStream(input);
|
||||
ZipEntry ze = zip.getNextEntry();
|
||||
while (ze!=null) {
|
||||
String resourceName = ze.getName();
|
||||
if (interestingResourceNames.test(resourceName)) {
|
||||
//Example url: jar:file:/home/kdvolder/.m2/repository/org/springframework/boot/spring-boot/2.1.4.RELEASE/spring-boot-2.1.4.RELEASE.jar!/META-INF/spring.factories
|
||||
// System.out.println("FOUND "+resourceName+" in "+url);
|
||||
requestor.put(resourceName, "jar:"+url+"!/"+ze);
|
||||
// } else {
|
||||
// System.out.println("mismatch: "+ze.getName());
|
||||
}
|
||||
ze = zip.getNextEntry();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SpringXmlNamespacesPlugin.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isZip(URL url) {
|
||||
String path = url.getPath();
|
||||
return path.endsWith(".jar") || path.endsWith(".zip");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<URL> getResources(String resourceName) {
|
||||
if (!shouldFilter(resourceName)) {
|
||||
Flux<URL> localResources =
|
||||
Flux.defer(() -> Flux.fromIterable(getResourcesCollection(resourceName)))
|
||||
.map(resource -> {
|
||||
try {
|
||||
return new URL(resource);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
return parent.getResources(resourceName)
|
||||
.concatWith(localResources);
|
||||
}
|
||||
return Flux.empty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,537 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2015 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Spring IDE Developers - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.classpath;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
import org.eclipse.core.resources.IPathVariableManager;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.IResourceChangeEvent;
|
||||
import org.eclipse.core.resources.IResourceChangeListener;
|
||||
import org.eclipse.core.resources.IResourceDelta;
|
||||
import org.eclipse.core.resources.IResourceDeltaVisitor;
|
||||
import org.eclipse.core.resources.IWorkspace;
|
||||
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
|
||||
import org.eclipse.jdt.core.ElementChangedEvent;
|
||||
import org.eclipse.jdt.core.IClasspathAttribute;
|
||||
import org.eclipse.jdt.core.IClasspathEntry;
|
||||
import org.eclipse.jdt.core.IElementChangedListener;
|
||||
import org.eclipse.jdt.core.IJavaElementDelta;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.JavaModelException;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.SpringXmlNamespacesPlugin;
|
||||
import org.springsource.ide.eclipse.commons.core.JdtUtils;
|
||||
|
||||
/**
|
||||
* Internal cache of classpath urls and corresponding resourceloaders.
|
||||
* @author Christian Dupuis
|
||||
* @author Martin Lippert
|
||||
* @since 2.2.5
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ProjectResourceLoaderCache {
|
||||
|
||||
private static final String FILE_SCHEME = "file";
|
||||
private static final int CACHE_SIZE = 200;
|
||||
private static final List<ResourceLoaderCacheEntry> RESOURCELOADER_CACHE = new ArrayList<ResourceLoaderCacheEntry>(CACHE_SIZE);
|
||||
|
||||
private static final String DEBUG_OPTION = SpringXmlNamespacesPlugin.PLUGIN_ID + "/java/resourceloader/debug";
|
||||
private static final boolean DEBUG_RESOURCELOADER = SpringXmlNamespacesPlugin.isDebug(DEBUG_OPTION);
|
||||
|
||||
private static IResourceChangeListener resourceChangeListener = null;
|
||||
|
||||
private static ResourceLoader addResourceLoaderToCache(IProject project, List<URL> urls, ResourceLoader parentResourceLoader) {
|
||||
synchronized (RESOURCELOADER_CACHE) {
|
||||
int nEntries = RESOURCELOADER_CACHE.size();
|
||||
if (nEntries >= CACHE_SIZE) {
|
||||
// find obsolete entries or remove entry that was least recently accessed
|
||||
ResourceLoaderCacheEntry oldest = null;
|
||||
List<ResourceLoaderCacheEntry> obsoleteResourceLoaders = new ArrayList<ResourceLoaderCacheEntry>(CACHE_SIZE);
|
||||
for (int i = 0; i < nEntries; i++) {
|
||||
ResourceLoaderCacheEntry entry = (ResourceLoaderCacheEntry) RESOURCELOADER_CACHE.get(i);
|
||||
IProject curr = entry.getProject();
|
||||
if (!curr.exists() || !curr.isAccessible() || !curr.isOpen()) {
|
||||
obsoleteResourceLoaders.add(entry);
|
||||
}
|
||||
else {
|
||||
if (oldest == null || entry.getLastAccess() < oldest.getLastAccess()) {
|
||||
oldest = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!obsoleteResourceLoaders.isEmpty()) {
|
||||
for (int i = 0; i < obsoleteResourceLoaders.size(); i++) {
|
||||
removeResourceLoaderEntryFromCache((ResourceLoaderCacheEntry) obsoleteResourceLoaders.get(i));
|
||||
}
|
||||
}
|
||||
else if (oldest != null) {
|
||||
removeResourceLoaderEntryFromCache(oldest);
|
||||
}
|
||||
}
|
||||
ResourceLoaderCacheEntry newEntry = new ResourceLoaderCacheEntry(project, urls, parentResourceLoader);
|
||||
RESOURCELOADER_CACHE.add(newEntry);
|
||||
return newEntry.getResourceLoader();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add {@link URL}s to the given set of <code>paths</code>.
|
||||
*/
|
||||
private static void addClassPathUrls(IProject project, List<URL> paths, Set<IProject> resolvedProjects) {
|
||||
|
||||
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
|
||||
|
||||
// add project to local cache to prevent adding its classpaths multiple times
|
||||
if (resolvedProjects.contains(project)) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
resolvedProjects.add(project);
|
||||
}
|
||||
|
||||
try {
|
||||
if (JdtUtils.isJavaProject(project)) {
|
||||
IJavaProject jp = JavaCore.create(project);
|
||||
// configured classpath
|
||||
IClasspathEntry[] classpath = jp.getResolvedClasspath(true);
|
||||
|
||||
// add class path entries
|
||||
for (int i = 0; i < classpath.length; i++) {
|
||||
IClasspathEntry path = classpath[i];
|
||||
if (path.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
|
||||
IPath entryPath = path.getPath();
|
||||
File file = entryPath.toFile();
|
||||
if (file.exists()) {
|
||||
paths.add(file.toURI().toURL());
|
||||
}
|
||||
else {
|
||||
// case for project relative links
|
||||
String projectName = entryPath.segment(0);
|
||||
IProject pathProject = root.getProject(projectName);
|
||||
covertPathToUrl(pathProject, paths, entryPath);
|
||||
}
|
||||
}
|
||||
else if (path.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
|
||||
// add source path as well for non java resources
|
||||
IPath sourcePath = path.getPath();
|
||||
covertPathToUrl(project, paths, sourcePath);
|
||||
// add source output locations for different source
|
||||
// folders
|
||||
IPath sourceOutputPath = path.getOutputLocation();
|
||||
covertPathToUrl(project, paths, sourceOutputPath);
|
||||
}
|
||||
}
|
||||
// add all depending java projects
|
||||
for (IJavaProject p : JdtUtils.getAllDependingJavaProjects(jp)) {
|
||||
addClassPathUrls(p.getProject(), paths, resolvedProjects);
|
||||
}
|
||||
|
||||
// get default output directory
|
||||
IPath outputPath = jp.getOutputLocation();
|
||||
covertPathToUrl(project, paths, outputPath);
|
||||
}
|
||||
else {
|
||||
for (IProject p : project.getReferencedProjects()) {
|
||||
addClassPathUrls(p, paths, resolvedProjects);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static void addUri(List<URL> paths, URI uri) throws MalformedURLException {
|
||||
File file = new File(uri);
|
||||
// If we keep the following check, non-existing output folders will never be used for the lifetime of
|
||||
// a resourceloader. this causes issues with clean projects with not-yet existing output folders.
|
||||
// if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
paths.add(new URL(uri.toString() + File.separator));
|
||||
}
|
||||
else {
|
||||
paths.add(uri.toURL());
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
private static void covertPathToUrl(IProject project, List<URL> paths, IPath path) throws MalformedURLException {
|
||||
if (path != null && project != null && path.removeFirstSegments(1) != null
|
||||
&& project.findMember(path.removeFirstSegments(1)) != null) {
|
||||
|
||||
URI uri = project.findMember(path.removeFirstSegments(1)).getRawLocationURI();
|
||||
|
||||
if (uri != null) {
|
||||
String scheme = uri.getScheme();
|
||||
if (FILE_SCHEME.equalsIgnoreCase(scheme)) {
|
||||
addUri(paths, uri);
|
||||
}
|
||||
else if ("sourcecontrol".equals(scheme)) {
|
||||
// special case of Rational Team Concert
|
||||
IPath sourceControlPath = project.findMember(path.removeFirstSegments(1)).getLocation();
|
||||
File sourceControlFile = sourceControlPath.toFile();
|
||||
if (sourceControlFile.exists()) {
|
||||
addUri(paths, sourceControlFile.toURI());
|
||||
}
|
||||
}
|
||||
else {
|
||||
IPathVariableManager variableManager = ResourcesPlugin.getWorkspace().getPathVariableManager();
|
||||
addUri(paths, variableManager.resolveURI(uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ResourceLoader findResourceLoaderInCache(IProject project, ResourceLoader parentResourceLoader) {
|
||||
synchronized (RESOURCELOADER_CACHE) {
|
||||
for (int i = RESOURCELOADER_CACHE.size() - 1; i >= 0; i--) {
|
||||
ResourceLoaderCacheEntry entry = (ResourceLoaderCacheEntry) RESOURCELOADER_CACHE.get(i);
|
||||
IProject curr = entry.getProject();
|
||||
if (curr == null || !curr.exists() || !curr.isAccessible() || !curr.isOpen()) {
|
||||
removeResourceLoaderEntryFromCache(entry);
|
||||
if (DEBUG_RESOURCELOADER) {
|
||||
System.out.println(String.format("> removing resourceloader for '%s' : total %s",
|
||||
entry.getProject(), RESOURCELOADER_CACHE.size()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (entry.matches(project, parentResourceLoader)) {
|
||||
entry.markAsAccessed();
|
||||
return entry.getResourceLoader();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates all class path entries of the given <code>project</code> and all depending projects.
|
||||
* <p>
|
||||
* Note: if <code>useParentResourceLoader</code> is true, the Spring, AspectJ, Commons Logging and ASM bundles are
|
||||
* automatically added to the paths.
|
||||
* @param project the {@link IProject}
|
||||
* @param useParentResourceLoader use the OSGi resourceloader as parent
|
||||
* @return a set of {@link URL}s that can be used to construct a {@link URLResourceLoader}
|
||||
*/
|
||||
public static List<URL> getClassPathUrls(IProject project, ResourceLoader parentResourceLoader) {
|
||||
|
||||
// needs to be linked to preserve ordering
|
||||
List<URL> paths = new ArrayList<URL>();
|
||||
Set<IProject> resolvedProjects = new HashSet<IProject>();
|
||||
addClassPathUrls(project, paths, resolvedProjects);
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers internal listeners that listen to changes relevant to clear out stale cache entries.
|
||||
*/
|
||||
private static void registerListenersIfRequired() {
|
||||
if (resourceChangeListener == null) {
|
||||
resourceChangeListener = new SourceAndOutputLocationResourceChangeListener();
|
||||
ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given {@link ResourceLoaderCacheEntry} from the internal cache.
|
||||
* @param entry the entry to remove
|
||||
*/
|
||||
private static void removeResourceLoaderEntryFromCache(ResourceLoaderCacheEntry entry) {
|
||||
synchronized (RESOURCELOADER_CACHE) {
|
||||
if (DEBUG_RESOURCELOADER) {
|
||||
System.out.println(String.format("> removing resourceloader for '%s' : total %s", entry.getProject()
|
||||
.getName(), RESOURCELOADER_CACHE.size()));
|
||||
}
|
||||
entry.dispose();
|
||||
RESOURCELOADER_CACHE.remove(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean shouldFilter(String name) {
|
||||
if ("commons-logging.properties".equals(name)) return true;
|
||||
if (name != null && name.startsWith("META-INF/services/")) {
|
||||
return (name.indexOf('/', 18) == -1
|
||||
&& !name.startsWith("org.springframework", 18));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ResourceLoader} for the given project.
|
||||
*/
|
||||
public static ResourceLoader getResourceLoader(IProject project, ResourceLoader parentResourceLoader) {
|
||||
synchronized (ProjectResourceLoaderCache.class) {
|
||||
// Setup the root class loader to be used when no explicit parent class loader is given
|
||||
if (parentResourceLoader==null) {
|
||||
parentResourceLoader = ResourceLoader.NULL;
|
||||
}
|
||||
if (project == null) {
|
||||
return parentResourceLoader;
|
||||
}
|
||||
|
||||
registerListenersIfRequired();
|
||||
}
|
||||
|
||||
ResourceLoader classLoader = findResourceLoaderInCache(project, parentResourceLoader);
|
||||
if (classLoader == null) {
|
||||
List<URL> urls = getClassPathUrls(project, parentResourceLoader);
|
||||
classLoader = addResourceLoaderToCache(project, urls, parentResourceLoader);
|
||||
if (DEBUG_RESOURCELOADER) {
|
||||
System.out.println(String.format("> creating new resourceloader for '%s' with parent '%s' : total %s",
|
||||
project.getName(), parentResourceLoader, RESOURCELOADER_CACHE.size()));
|
||||
}
|
||||
}
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any cached {@link ResourceLoaderCacheEntry} for the given {@link IProject}.
|
||||
* @param project the project to remove {@link ResourceLoaderCacheEntry} for
|
||||
*/
|
||||
protected static void removeResourceLoaderEntryFromCache(IProject project) {
|
||||
synchronized (RESOURCELOADER_CACHE) {
|
||||
if (DEBUG_RESOURCELOADER) {
|
||||
System.out.println(String.format("> removing resourceloader for '%s' : total %s", project.getName(),
|
||||
RESOURCELOADER_CACHE.size()));
|
||||
}
|
||||
for (ResourceLoaderCacheEntry entry : new ArrayList<ResourceLoaderCacheEntry>(RESOURCELOADER_CACHE)) {
|
||||
if (project.equals(entry.getProject())) {
|
||||
entry.dispose();
|
||||
RESOURCELOADER_CACHE.remove(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal cache entry
|
||||
*/
|
||||
static class ResourceLoaderCacheEntry implements IElementChangedListener {
|
||||
|
||||
private URL[] directories;
|
||||
|
||||
private ResourceLoader jarResourceLoader;
|
||||
|
||||
private long lastAccess;
|
||||
|
||||
private ResourceLoader parentResourceLoader;
|
||||
|
||||
private IProject project;
|
||||
|
||||
private URL[] urls;
|
||||
|
||||
public ResourceLoaderCacheEntry(IProject project, List<URL> urls, ResourceLoader parentResourceLoader) {
|
||||
this.project = project;
|
||||
this.urls = urls.toArray(new URL[urls.size()]);
|
||||
this.parentResourceLoader = parentResourceLoader;
|
||||
markAsAccessed();
|
||||
JavaCore.addElementChangedListener(this, ElementChangedEvent.POST_CHANGE);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
JavaCore.removeElementChangedListener(this);
|
||||
this.urls = null;
|
||||
this.jarResourceLoader = null;
|
||||
}
|
||||
|
||||
public void elementChanged(ElementChangedEvent event) {
|
||||
IJavaProject javaProject = JdtUtils.getJavaProject(project);
|
||||
if (javaProject != null) {
|
||||
for (IJavaElementDelta delta : event.getDelta().getAffectedChildren()) {
|
||||
if ((delta.getFlags() & IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED) != 0
|
||||
|| (delta.getFlags() & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0) {
|
||||
if (javaProject.equals(delta.getElement()) || javaProject.isOnClasspath(delta.getElement())) {
|
||||
removeResourceLoaderEntryFromCache(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceLoader getResourceLoader() {
|
||||
ResourceLoader parent = getJarResourceLoader();
|
||||
return new FilteringURLResourceLoader(directories, parent);
|
||||
}
|
||||
|
||||
public long getLastAccess() {
|
||||
return lastAccess;
|
||||
}
|
||||
|
||||
public IProject getProject() {
|
||||
return this.project;
|
||||
}
|
||||
|
||||
public void markAsAccessed() {
|
||||
lastAccess = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean matches(IProject project, ResourceLoader parentResourceLoader) {
|
||||
return this.project.equals(project)
|
||||
&& ((parentResourceLoader == null && this.parentResourceLoader == null) || (parentResourceLoader != null && parentResourceLoader
|
||||
.equals(this.parentResourceLoader)));
|
||||
}
|
||||
|
||||
private synchronized ResourceLoader getJarResourceLoader() {
|
||||
if (jarResourceLoader == null) {
|
||||
Set<URL> jars = new LinkedHashSet<URL>();
|
||||
List<URL> dirs = new ArrayList<URL>();
|
||||
for (URL url : urls) {
|
||||
if (shouldLoadFromParent(url)) {
|
||||
jars.add(url);
|
||||
}
|
||||
else {
|
||||
dirs.add(url);
|
||||
}
|
||||
}
|
||||
if (parentResourceLoader == null) {
|
||||
parentResourceLoader = ResourceLoader.NULL;
|
||||
}
|
||||
jarResourceLoader = new FilteringURLResourceLoader((URL[]) jars.toArray(new URL[jars.size()]),
|
||||
parentResourceLoader);
|
||||
directories = dirs.toArray(new URL[dirs.size()]);
|
||||
}
|
||||
return jarResourceLoader;
|
||||
}
|
||||
|
||||
private boolean shouldLoadFromParent(URL url) {
|
||||
String path = url.getPath();
|
||||
if (path.endsWith(".jar") || path.endsWith(".zip")) {
|
||||
return true;
|
||||
}
|
||||
else if (path.contains("/org.eclipse.osgi/bundles/")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IResourceChangeListener} to clear the cache whenever new source or output folders are being added.
|
||||
* @since 2.5.2
|
||||
*/
|
||||
static class SourceAndOutputLocationResourceChangeListener implements IResourceChangeListener {
|
||||
|
||||
private static final int VISITOR_FLAGS = IResourceDelta.ADDED | IResourceDelta.CHANGED;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void resourceChanged(IResourceChangeEvent event) {
|
||||
if (event.getSource() instanceof IWorkspace) {
|
||||
int eventType = event.getType();
|
||||
switch (eventType) {
|
||||
case IResourceChangeEvent.POST_CHANGE:
|
||||
IResourceDelta delta = event.getDelta();
|
||||
if (delta != null) {
|
||||
try {
|
||||
delta.accept(getVisitor(), VISITOR_FLAGS);
|
||||
}
|
||||
catch (CoreException e) {
|
||||
SpringXmlNamespacesPlugin.log("Error while traversing resource change delta", e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (event.getSource() instanceof IProject) {
|
||||
int eventType = event.getType();
|
||||
switch (eventType) {
|
||||
case IResourceChangeEvent.POST_CHANGE:
|
||||
IResourceDelta delta = event.getDelta();
|
||||
if (delta != null) {
|
||||
try {
|
||||
delta.accept(getVisitor(), VISITOR_FLAGS);
|
||||
}
|
||||
catch (CoreException e) {
|
||||
SpringXmlNamespacesPlugin.log("Error while traversing resource change delta", e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected IResourceDeltaVisitor getVisitor() {
|
||||
return new SourceAndOutputLocationResourceVisitor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal resource delta visitor.
|
||||
*/
|
||||
protected class SourceAndOutputLocationResourceVisitor implements IResourceDeltaVisitor {
|
||||
|
||||
public final boolean visit(IResourceDelta delta) throws CoreException {
|
||||
IResource resource = delta.getResource();
|
||||
switch (delta.getKind()) {
|
||||
case IResourceDelta.ADDED:
|
||||
return resourceAdded(resource);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean resourceAdded(IResource resource) {
|
||||
if (resource instanceof IFolder && JdtUtils.isJavaProject(resource)) {
|
||||
try {
|
||||
IJavaProject javaProject = JdtUtils.getJavaProject(resource);
|
||||
// Safe guard once again
|
||||
if (javaProject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the default output location
|
||||
if (javaProject.getOutputLocation() != null
|
||||
&& javaProject.getOutputLocation().equals(resource.getFullPath())) {
|
||||
removeResourceLoaderEntryFromCache(resource.getProject());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check any source and output folder location
|
||||
for (IClasspathEntry entry : javaProject.getRawClasspath()) {
|
||||
if (resource.getFullPath() != null && resource.getFullPath().equals(entry.getPath())) {
|
||||
removeResourceLoaderEntryFromCache(resource.getProject());
|
||||
return false;
|
||||
}
|
||||
else if (resource.getFullPath() != null
|
||||
&& resource.getFullPath().equals(entry.getOutputLocation())) {
|
||||
removeResourceLoaderEntryFromCache(resource.getProject());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JavaModelException e) {
|
||||
SpringXmlNamespacesPlugin.log("Error traversing resource change delta", e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ide.eclipse.xml.namespaces.classpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.SpringXmlNamespacesPlugin;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Convenient utility methods for loading of {@code java.util.Properties},
|
||||
* performing standard handling of input streams.
|
||||
*
|
||||
* <p>For more configurable properties loading, including the option of a
|
||||
* customized encoding, consider using the PropertiesLoaderSupport class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @since 2.0
|
||||
* @see PropertiesLoaderSupport
|
||||
*/
|
||||
public abstract class PropertiesLoaderUtils {
|
||||
|
||||
private static final String XML_FILE_EXTENSION = ".xml";
|
||||
|
||||
/**
|
||||
* Load all properties from the specified class path resource
|
||||
* (in ISO-8859-1 encoding), using the given class loader.
|
||||
* <p>Merges properties if more than one resource of the same name
|
||||
* found in the class path.
|
||||
* @param resourceName the name of the class path resource
|
||||
* @param classLoader the ClassLoader to use for loading
|
||||
* (or {@code null} to use the default class loader)
|
||||
* @return the populated Properties instance
|
||||
* @throws IOException if loading failed
|
||||
*/
|
||||
public static Properties loadAllProperties(String resourceName, ResourceLoader classLoader) {
|
||||
Assert.isNotNull(resourceName, "Resource name must not be null");
|
||||
ResourceLoader classLoaderToUse = classLoader;
|
||||
if (classLoaderToUse == null) {
|
||||
classLoaderToUse = ResourceLoader.NULL;
|
||||
}
|
||||
Flux<URL> urls = classLoaderToUse.getResources(resourceName);
|
||||
Mono<Properties> propsMono = urls.reduceWith(Properties::new,
|
||||
(props, url) -> {
|
||||
try {
|
||||
URLConnection con = url.openConnection();
|
||||
useCachesIfNecessary(con);
|
||||
InputStream is = con.getInputStream();
|
||||
try {
|
||||
if (resourceName.endsWith(XML_FILE_EXTENSION)) {
|
||||
props.loadFromXML(is);
|
||||
}
|
||||
else {
|
||||
props.load(is);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
SpringXmlNamespacesPlugin.log(e);
|
||||
}
|
||||
return props;
|
||||
}
|
||||
);
|
||||
return propsMono.block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link URLConnection#setUseCaches "useCaches"} flag on the
|
||||
* given connection, preferring {@code false} but leaving the
|
||||
* flag at {@code true} for JNLP based resources.
|
||||
* @param con the URLConnection to set the flag on
|
||||
*/
|
||||
private static void useCachesIfNecessary(URLConnection con) {
|
||||
con.setUseCaches(con.getClass().getSimpleName().startsWith("JNLP"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.classpath;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* Subset of {@link ClassLoader} interface. Mimicks behavior of
|
||||
* classloaders but only can be used to load 'resources' as data.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public abstract class ResourceLoader {
|
||||
|
||||
public static final ResourceLoader NULL = new ResourceLoader() {
|
||||
@Override
|
||||
public Flux<URL> getResources(String resourceName) {
|
||||
return Flux.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResourceLoader.NULL";
|
||||
}
|
||||
};
|
||||
|
||||
public final URL getResource(String resourceName) {
|
||||
return getResources(resourceName).blockFirst();
|
||||
}
|
||||
protected abstract Flux<URL> getResources(String resourceName);
|
||||
|
||||
public final InputStream getResourceAsStream(String name) {
|
||||
URL url = getResource(name);
|
||||
try {
|
||||
return url != null ? url.openStream() : null;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2006, 2013 VMware Inc., Oracle Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Apache License v2.0 which accompanies this distribution.
|
||||
* The Eclipse Public License is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
|
||||
* is available at https://www.opensource.org/licenses/apache2.0.php.
|
||||
* You may elect to redistribute this code under either of these licenses.
|
||||
*
|
||||
* Contributors:
|
||||
* VMware Inc.
|
||||
* Oracle Inc.
|
||||
*****************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
* ClassLoader backed by an OSGi bundle. Provides the ability to use a separate
|
||||
* class loader as fall back.
|
||||
*
|
||||
* Contains facilities for tracing class loading behaviour so that issues can be
|
||||
* easily resolved.
|
||||
*
|
||||
* For debugging please see {@link DebugUtils}.
|
||||
*
|
||||
* This class is copied and modified from the original source code from the
|
||||
* Eclipse Gemini Blueprint project.
|
||||
*
|
||||
* @author Adrian Colyer
|
||||
* @author Andy Piper
|
||||
* @author Costin Leau
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class BundleDelegatingClassLoader extends ClassLoader {
|
||||
|
||||
private static final String NULL_STRING = "null";
|
||||
|
||||
private static final Enumeration<URL> EMPTY_RESOURCES = new Enumeration<URL>() {
|
||||
public boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
public URL nextElement() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Transparently enumerates across two enumerations.
|
||||
*/
|
||||
private static class CombinedEnumeration<T> implements Enumeration<T> {
|
||||
private final Enumeration<T> e1;
|
||||
private final Enumeration<T> e2;
|
||||
|
||||
public CombinedEnumeration(Enumeration<T> e1, Enumeration<T> e2) {
|
||||
this.e1 = e1;
|
||||
this.e2 = e2;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return e1.hasMoreElements() || e2.hasMoreElements();
|
||||
}
|
||||
|
||||
public T nextElement() {
|
||||
if (e1.hasMoreElements()) {
|
||||
return e1.nextElement();
|
||||
}
|
||||
if (e2.hasMoreElements()) {
|
||||
return e2.nextElement();
|
||||
}
|
||||
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
private final ClassLoader bridge;
|
||||
|
||||
private final Bundle backingBundle;
|
||||
|
||||
|
||||
/**
|
||||
* Factory method for creating a class loader over the given bundle.
|
||||
*
|
||||
* @param aBundle bundle to use for class loading and resource acquisition
|
||||
* @return class loader adapter over the given bundle
|
||||
*/
|
||||
public static BundleDelegatingClassLoader createBundleClassLoaderFor(Bundle aBundle) {
|
||||
return createBundleClassLoaderFor(aBundle, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating a class loader over the given bundle and with
|
||||
* a given class loader as fall-back. In case the bundle cannot find a class
|
||||
* or locate a resource, the given class loader will be used as fall back.
|
||||
*
|
||||
* @param bundle bundle used for class loading and resource acquisition
|
||||
* @param bridge class loader used as fall back in case the bundle cannot
|
||||
* load a class or find a resource. Can be <code>null</code>
|
||||
* @return class loader adapter over the given bundle and class loader
|
||||
*/
|
||||
public static BundleDelegatingClassLoader createBundleClassLoaderFor(final Bundle bundle, final ClassLoader bridge) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<BundleDelegatingClassLoader>() {
|
||||
|
||||
public BundleDelegatingClassLoader run() {
|
||||
return new BundleDelegatingClassLoader(bundle, bridge);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*
|
||||
* Constructs a new <code>BundleDelegatingClassLoader</code> instance.
|
||||
*
|
||||
* @param bundle
|
||||
* @param bridgeLoader
|
||||
*/
|
||||
protected BundleDelegatingClassLoader(Bundle bundle, ClassLoader bridgeLoader) {
|
||||
super(null);
|
||||
Assert.isNotNull(bundle, "bundle should be non-null");
|
||||
this.backingBundle = bundle;
|
||||
this.bridge = bridgeLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
try {
|
||||
return this.backingBundle.loadClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException cnfe) {
|
||||
throw new ClassNotFoundException(name + " not found from bundle [" + backingBundle.getSymbolicName() + "]",
|
||||
cnfe);
|
||||
}
|
||||
catch (NoClassDefFoundError ncdfe) {
|
||||
// This is almost always an error
|
||||
// This is caused by a dependent class failure,
|
||||
// so make sure we search for the right one.
|
||||
NoClassDefFoundError e = new NoClassDefFoundError(name + " not found from bundle ["
|
||||
+ nullSafeNameAndSymName(backingBundle) + "]");
|
||||
e.initCause(ncdfe);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URL findResource(String name) {
|
||||
URL url = this.backingBundle.getResource(name);
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Enumeration<URL> findResources(String name) throws IOException {
|
||||
Enumeration<URL> enm = this.backingBundle.getResources(name);
|
||||
return enm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<URL> getResources(String name) throws IOException {
|
||||
Enumeration<URL> resources = this.backingBundle.getResources(name);
|
||||
|
||||
if (this.bridge != null) {
|
||||
Enumeration<URL> bridgeResources = this.bridge.getResources(name);
|
||||
if (resources == null) {
|
||||
resources = bridgeResources;
|
||||
} else if (bridgeResources != null){
|
||||
resources = new CombinedEnumeration<URL>(resources, bridgeResources);
|
||||
}
|
||||
}
|
||||
|
||||
// Classloader contract: Never return null but rather an empty enumeration.
|
||||
return resources != null ? resources : EMPTY_RESOURCES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getResource(String name) {
|
||||
URL resource = findResource(name);
|
||||
if (bridge != null && resource == null) {
|
||||
resource = bridge.getResource(name);
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = findClass(name);
|
||||
}
|
||||
catch (ClassNotFoundException cnfe) {
|
||||
if (bridge != null)
|
||||
clazz = bridge.loadClass(name);
|
||||
else
|
||||
throw cnfe;
|
||||
}
|
||||
if (resolve) {
|
||||
resolveClass(clazz);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BundleDelegatingClassLoader for [" + nullSafeNameAndSymName(backingBundle) + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle to which this class loader delegates calls to.
|
||||
*
|
||||
* @return the backing bundle
|
||||
*/
|
||||
public Bundle getBundle() {
|
||||
return backingBundle;
|
||||
}
|
||||
|
||||
protected String nullSafeNameAndSymName(Bundle bundle) {
|
||||
if (bundle == null)
|
||||
return NULL_STRING;
|
||||
|
||||
Dictionary<String, String> dict = bundle.getHeaders();
|
||||
|
||||
if (dict == null)
|
||||
return NULL_STRING;
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
String name = dict.get(org.osgi.framework.Constants.BUNDLE_NAME);
|
||||
if (name == null)
|
||||
buf.append(NULL_STRING);
|
||||
else
|
||||
buf.append(name);
|
||||
buf.append(" (");
|
||||
String sname = dict.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME);
|
||||
|
||||
if (sname == null)
|
||||
buf.append(NULL_STRING);
|
||||
else
|
||||
buf.append(sname);
|
||||
|
||||
buf.append(")");
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013, 2014 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Spring IDE Developers - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.internal;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolverExtension;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.ProjectAwareUrlStreamHandlerService;
|
||||
|
||||
/**
|
||||
* {@link URIResolverExtension} resolves the physical location of schema files on the project classpath using the
|
||||
* special project-aware protocol that {@link ProjectClasspathExtensibleUriResolver} uses.
|
||||
*
|
||||
* @author Martin Lippert
|
||||
* @since 3.2.0
|
||||
*/
|
||||
@SuppressWarnings({ "restriction" })
|
||||
public class ProjectClasspathExtensibleUriPhysicalLocationResolver implements URIResolverExtension {
|
||||
|
||||
public ProjectClasspathExtensibleUriPhysicalLocationResolver() {
|
||||
}
|
||||
|
||||
public String resolve(IFile file, String baseLocation, String publicId, String systemId) {
|
||||
if (systemId != null && systemId.startsWith(ProjectAwareUrlStreamHandlerService.PROJECT_AWARE_PROTOCOL_HEADER)) {
|
||||
String nameAndLocation = systemId.substring(ProjectAwareUrlStreamHandlerService.PROJECT_AWARE_PROTOCOL_HEADER.length());
|
||||
String realSystemId = nameAndLocation.substring(nameAndLocation.indexOf('/') + 1);
|
||||
return realSystemId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010, 2014 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Spring IDE Developers - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
|
||||
import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
|
||||
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
|
||||
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
|
||||
import org.eclipse.jdt.core.ElementChangedEvent;
|
||||
import org.eclipse.jdt.core.IElementChangedListener;
|
||||
import org.eclipse.jdt.core.IJavaElement;
|
||||
import org.eclipse.jdt.core.IJavaElementDelta;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolverExtension;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.ProjectAwareUrlStreamHandlerService;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.SpringXmlNamespacesPlugin;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.XmlNamespaceUtils;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.util.DocumentAccessor;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.util.DocumentAccessor.SchemaLocations;
|
||||
import org.springsource.ide.eclipse.commons.core.JdtUtils;
|
||||
import org.springsource.ide.eclipse.commons.core.SpringCorePreferences;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
/**
|
||||
* {@link URIResolverExtension} resolves URIs on the project classpath using the
|
||||
* protocol established by <code>spring.schemas</code> files.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @author Martin Lippert
|
||||
* @since 2.3.1
|
||||
*/
|
||||
@SuppressWarnings({ "restriction", "deprecation" })
|
||||
public class ProjectClasspathExtensibleUriResolver implements
|
||||
URIResolverExtension, IElementChangedListener, IPropertyChangeListener,
|
||||
IPreferenceChangeListener {
|
||||
|
||||
private static final String KEY_DISABLE_CACHING_PREFERENCE = SpringXmlNamespacesPlugin.PLUGIN_ID + "."
|
||||
+ SpringXmlNamespacesPlugin.DISABLE_CACHING_FOR_NAMESPACE_LOADING_ID;
|
||||
|
||||
// private static Map<IProject, ProjectClasspathUriResolver> projectResolvers = new ConcurrentHashMap<IProject, ProjectClasspathUriResolver>();
|
||||
private static ConcurrentMap<IProject, Future<ProjectClasspathUriResolver>> projectResolvers = new ConcurrentHashMap<IProject, Future<ProjectClasspathUriResolver>>();
|
||||
|
||||
public ProjectClasspathExtensibleUriResolver() {
|
||||
JavaCore.addElementChangedListener(this,
|
||||
ElementChangedEvent.POST_CHANGE);
|
||||
SpringXmlNamespacesPlugin.getDefault().getPluginPreferences()
|
||||
.addPropertyChangeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String resolve(IFile file, String baseLocation, String publicId,
|
||||
String systemId) {
|
||||
// systemId is already resolved; so don't touch
|
||||
if (systemId != null && systemId.startsWith("jar:")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// identify the correct project
|
||||
IProject project = null;
|
||||
if (file != null) {
|
||||
project = getBestMatchingProject(file);
|
||||
} else if (baseLocation != null
|
||||
&& baseLocation.startsWith(ProjectAwareUrlStreamHandlerService.PROJECT_AWARE_PROTOCOL_HEADER)) {
|
||||
String nameAndLocation = baseLocation
|
||||
.substring(ProjectAwareUrlStreamHandlerService.PROJECT_AWARE_PROTOCOL_HEADER
|
||||
.length());
|
||||
String projectName = nameAndLocation.substring(0, nameAndLocation.indexOf('/'));
|
||||
project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
|
||||
}
|
||||
|
||||
// // continue just for identified Spring projects
|
||||
// if (project == null || BeansCorePlugin.getModel().getProject(project) == null) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
if (systemId == null && file != null) {
|
||||
systemId = findSystemIdFromFile(file, publicId);
|
||||
}
|
||||
|
||||
if (systemId == null && publicId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ProjectClasspathUriResolver resolver = getProjectResolver(file, project);
|
||||
if (resolver != null) {
|
||||
String resolved = resolver.resolveOnClasspath(publicId, systemId);
|
||||
if (resolved != null) {
|
||||
resolved = ProjectAwareUrlStreamHandlerService.createProjectAwareUrl(project.getName(), resolved);
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IProject getBestMatchingProject(IFile file) {
|
||||
IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(file.getLocationURI());
|
||||
if (files != null && files.length == 1) {
|
||||
return files[0].getProject();
|
||||
}
|
||||
else if (files != null && files.length > 1) {
|
||||
IFile shortestPathFile = files[0];
|
||||
int shortestPathSegmentCount = shortestPathFile.getFullPath().segmentCount();
|
||||
|
||||
for (int i = 1; i < files.length; i++) {
|
||||
int segmentCount = files[i].getFullPath().segmentCount();
|
||||
if (segmentCount < shortestPathSegmentCount) {
|
||||
shortestPathFile = files[i];
|
||||
shortestPathSegmentCount = segmentCount;
|
||||
}
|
||||
}
|
||||
return shortestPathFile.getProject();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ProjectClasspathUriResolver getProjectResolver(final IFile file, final IProject project) {
|
||||
// // no project resolver if not a spring project
|
||||
// IBeansProject beansProject = BeansCorePlugin.getModel().getProject(project);
|
||||
// if (beansProject == null) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
if (!XmlNamespaceUtils.useNamespacesFromClasspath(project)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (file != null && !checkFileExtension(file/*, beansProject*/)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Special case for 'pom.xml'. We can skip it entirely because it is not used to define spring beans.
|
||||
// Also... m2e apparantly causes this to be called directly from the UI thread causing major hangs / annoyance.
|
||||
// See: https://github.com/spring-projects/sts4/issues/318
|
||||
if (file != null && "pom.xml".equals(file.getName())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
Future<ProjectClasspathUriResolver> future = projectResolvers.get(project);
|
||||
if (future == null) {
|
||||
|
||||
Callable<ProjectClasspathUriResolver> createResolver = new Callable<ProjectClasspathUriResolver>() {
|
||||
public ProjectClasspathUriResolver call() throws InterruptedException {
|
||||
ProjectClasspathUriResolver resolver = new ProjectClasspathUriResolver(
|
||||
project);
|
||||
|
||||
SpringCorePreferences
|
||||
.getProjectPreferences(project, SpringXmlNamespacesPlugin.PLUGIN_ID)
|
||||
.getProjectPreferences().addPreferenceChangeListener(ProjectClasspathExtensibleUriResolver.this);
|
||||
|
||||
return resolver;
|
||||
}
|
||||
};
|
||||
|
||||
FutureTask<ProjectClasspathUriResolver> futureTask = new FutureTask<ProjectClasspathUriResolver>(createResolver);
|
||||
future = projectResolvers.putIfAbsent(project, futureTask);
|
||||
if (future == null) {
|
||||
future = futureTask;
|
||||
futureTask.run();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return future.get();
|
||||
}
|
||||
catch (CancellationException e) {
|
||||
projectResolvers.remove(project, future);
|
||||
return null;
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
return null;
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void elementChanged(ElementChangedEvent event) {
|
||||
for (IJavaElementDelta delta : event.getDelta().getAffectedChildren()) {
|
||||
if ((delta.getFlags() & IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED) != 0
|
||||
|| (delta.getFlags() & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0) {
|
||||
resetForChangedElement(delta.getElement());
|
||||
} else if ((delta.getFlags() & IJavaElementDelta.F_CLOSED) != 0) {
|
||||
resetForChangedElement(delta.getElement());
|
||||
} else if ((delta.getFlags() & IJavaElementDelta.F_OPENED) != 0) {
|
||||
resetForChangedElement(delta.getElement());
|
||||
} else if ((delta.getKind() & IJavaElementDelta.REMOVED) != 0) {
|
||||
resetForChangedElement(delta.getElement());
|
||||
} else if ((delta.getKind() & IJavaElementDelta.ADDED) != 0) {
|
||||
resetForChangedElement(delta.getElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void propertyChange(PropertyChangeEvent event) {
|
||||
if (SpringXmlNamespacesPlugin.DISABLE_CACHING_FOR_NAMESPACE_LOADING_ID
|
||||
.equals(event.getProperty())) {
|
||||
projectResolvers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void preferenceChange(PreferenceChangeEvent event) {
|
||||
if (KEY_DISABLE_CACHING_PREFERENCE.equals(event.getKey())) {
|
||||
projectResolvers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void resetForChangedElement(IJavaElement element) {
|
||||
if (element instanceof IJavaProject) {
|
||||
IProject project = ((IJavaProject) element).getProject();
|
||||
projectResolvers.remove(project);
|
||||
SpringCorePreferences
|
||||
.getProjectPreferences(project, SpringXmlNamespacesPlugin.PLUGIN_ID)
|
||||
.getProjectPreferences()
|
||||
.removePreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
for (IProject project : projectResolvers.keySet()) {
|
||||
IJavaProject javaProject = JdtUtils.getJavaProject(project);
|
||||
if (javaProject != null) {
|
||||
if (javaProject.isOnClasspath(element)) {
|
||||
projectResolvers.remove(project);
|
||||
|
||||
SpringCorePreferences
|
||||
.getProjectPreferences(project,
|
||||
SpringXmlNamespacesPlugin.PLUGIN_ID)
|
||||
.getProjectPreferences()
|
||||
.removePreferenceChangeListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* try to extract the system-id of the given namespace from the xml file
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
private String findSystemIdFromFile(IFile file, String publicIc) {
|
||||
InputStream contents = null;
|
||||
try {
|
||||
contents = file.getContents();
|
||||
DocumentBuilderFactory builderFactory = DocumentBuilderFactory
|
||||
.newInstance();
|
||||
builderFactory.setValidating(false);
|
||||
builderFactory.setNamespaceAware(true);
|
||||
|
||||
builderFactory.setFeature("http://xml.org/sax/features/validation", false);
|
||||
builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
|
||||
builderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
||||
|
||||
DocumentBuilder builder = builderFactory.newDocumentBuilder();
|
||||
Document doc = builder.parse(contents);
|
||||
|
||||
DocumentAccessor accessor = new DocumentAccessor();
|
||||
accessor.pushDocument(doc);
|
||||
SchemaLocations locations = accessor.getCurrentSchemaLocations();
|
||||
|
||||
String location = locations.getSchemaLocation(publicIc);
|
||||
return location;
|
||||
} catch (Exception e) {
|
||||
// do nothing, systemId cannot be identified
|
||||
} finally {
|
||||
if (contents != null) {
|
||||
try {
|
||||
contents.close();
|
||||
} catch (IOException e) {
|
||||
// do nothing, systemId cannot be identified
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the file has a valid file extension.
|
||||
*/
|
||||
private boolean checkFileExtension(IFile file/*, IBeansProject project*/) {
|
||||
if (/*project.*/getConfigSuffixes() != null) {
|
||||
for (String extension : /*project.*/getConfigSuffixes()) {
|
||||
if (file.getName().endsWith(extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file.getName().endsWith(".xsd")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private String[] getConfigSuffixes() {
|
||||
return new String[]{ ".xml" };
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2010, 2011 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Spring IDE Developers - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.internal;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
|
||||
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
|
||||
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.NamespaceManagerProvider;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.SpringXmlNamespacesPlugin;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.XmlNamespaceUtils;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.classpath.ProjectResourceLoaderCache;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.classpath.PropertiesLoaderUtils;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.classpath.ResourceLoader;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.INamespaceDefinition;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.INamespaceDefinitionListener;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.INamespaceDefinitionResolver;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.NamespaceDefinition;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.util.TargetNamespaceScanner;
|
||||
import org.springsource.ide.eclipse.commons.core.SpringCorePreferences;
|
||||
import org.springsource.ide.eclipse.commons.core.util.CollectionUtils;
|
||||
import org.springsource.ide.eclipse.commons.core.util.FileCopyUtils;
|
||||
import org.springsource.ide.eclipse.commons.frameworks.core.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link INamespaceDefinitionResolver} that resolves {@link INamespaceDefinition}s from the project's classpath as
|
||||
* well.
|
||||
* <p>
|
||||
* Note: this implementation is currently not in use
|
||||
* @author Christian Dupuis
|
||||
* @author Martin Lippert
|
||||
* @since 2.3.1
|
||||
* @see BeansCorePlugin#getNamespaceDefinitionResolver(IProject)
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ProjectClasspathNamespaceDefinitionResolver implements INamespaceDefinitionResolver {
|
||||
|
||||
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
|
||||
|
||||
public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";
|
||||
|
||||
public static final String DEFAULT_TOOLING_MAPPINGS_LOCATION = "META-INF/spring.tooling";
|
||||
|
||||
private Map<String, NamespaceDefinition> namespaceDefinitionRegistry = null;
|
||||
|
||||
private final IProject project;
|
||||
|
||||
private EnablementPropertyChangeListener propertyChangeListener;
|
||||
|
||||
private final INamespaceDefinitionResolver resolver;
|
||||
|
||||
public ProjectClasspathNamespaceDefinitionResolver(IProject project) {
|
||||
this.project = project;
|
||||
this.resolver = SpringXmlNamespacesPlugin.getNamespaceDefinitionResolver();
|
||||
|
||||
init();
|
||||
|
||||
registerListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose this resolver instance.
|
||||
*/
|
||||
public void dispose() {
|
||||
unRegisterListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Set<INamespaceDefinition> getNamespaceDefinitions() {
|
||||
return new HashSet<INamespaceDefinition>(namespaceDefinitionRegistry.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public INamespaceDefinition resolveNamespaceDefinition(String namespaceUri) {
|
||||
return namespaceDefinitionRegistry.get(namespaceUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all {@link NamespaceDefinition}s from the project classpath. Also handle extraction of icon file.
|
||||
*/
|
||||
private void init() {
|
||||
|
||||
// long start = System.currentTimeMillis();
|
||||
|
||||
this.namespaceDefinitionRegistry = new ConcurrentHashMap<String, NamespaceDefinition>();
|
||||
|
||||
// Add in namespace definitions from the classpath
|
||||
if (XmlNamespaceUtils.useNamespacesFromClasspath(project)) {
|
||||
|
||||
ResourceLoader cls = ProjectResourceLoaderCache.getResourceLoader(project, null);
|
||||
|
||||
Map<String, String> handlerMappings = new HashMap<String, String>();
|
||||
Map<String, String> toolingMappings = new HashMap<String, String>();
|
||||
Properties schemaMappings = new Properties();
|
||||
|
||||
// try {
|
||||
Properties mappings = PropertiesLoaderUtils.loadAllProperties(DEFAULT_HANDLER_MAPPINGS_LOCATION, cls);
|
||||
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
|
||||
schemaMappings = PropertiesLoaderUtils.loadAllProperties(DEFAULT_SCHEMA_MAPPINGS_LOCATION, cls);
|
||||
mappings = PropertiesLoaderUtils.loadAllProperties(DEFAULT_TOOLING_MAPPINGS_LOCATION, cls);
|
||||
CollectionUtils.mergePropertiesIntoMap(mappings, toolingMappings);
|
||||
// }
|
||||
// catch (IOException e) {
|
||||
// }
|
||||
|
||||
for (Object xsd : schemaMappings.keySet()) {
|
||||
String key = xsd.toString();
|
||||
|
||||
String schemaUri = schemaMappings.getProperty(key);
|
||||
URL url = cls.getResource(schemaUri);
|
||||
|
||||
// fallback, if schema location starts with / and therefore fails to be found by classloader
|
||||
if (url == null && schemaUri.startsWith("/")) {
|
||||
schemaUri = schemaUri.substring(1);
|
||||
url = cls.getResource(schemaUri);
|
||||
}
|
||||
|
||||
if (url == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String namespaceUri = TargetNamespaceScanner.getTargetNamespace(url);
|
||||
|
||||
if (StringUtils.hasText(namespaceUri)) {
|
||||
|
||||
String icon = toolingMappings.get(namespaceUri + "@icon");
|
||||
String prefix = toolingMappings.get(namespaceUri + "@prefix");
|
||||
String name = toolingMappings.get(namespaceUri + "@name");
|
||||
|
||||
if (namespaceDefinitionRegistry.containsKey(namespaceUri)) {
|
||||
namespaceDefinitionRegistry.get(namespaceUri).addSchemaLocation(key);
|
||||
namespaceDefinitionRegistry.get(namespaceUri).addUri(schemaUri);
|
||||
}
|
||||
else {
|
||||
File iconFile = extractIcon(namespaceUri, icon, cls);
|
||||
|
||||
NamespaceDefinition namespaceDefinition = new ExternalImageNamespaceDefinition(schemaMappings,
|
||||
iconFile);
|
||||
namespaceDefinition.setName(name);
|
||||
namespaceDefinition.setPrefix(prefix);
|
||||
namespaceDefinition.setIconPath(icon);
|
||||
namespaceDefinition.addSchemaLocation(key);
|
||||
namespaceDefinition.setNamespaceUri(namespaceUri);
|
||||
namespaceDefinition.addUri(schemaUri);
|
||||
|
||||
namespaceDefinitionRegistry.put(namespaceUri, namespaceDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (INamespaceDefinition namespaceDefinition : resolver.getNamespaceDefinitions()) {
|
||||
namespaceDefinitionRegistry.put(namespaceDefinition.getNamespaceUri(),
|
||||
(NamespaceDefinition) namespaceDefinition);
|
||||
}
|
||||
}
|
||||
// System.out.println(String.format("-- loading of namespace definitions took '%s'ms",
|
||||
// (System.currentTimeMillis() - start)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract icon files from the given classloader and store it on the filesystem for later use.
|
||||
*/
|
||||
private File extractIcon(String namespaceUri, String icon, ResourceLoader cls) {
|
||||
if (StringUtils.hasLength(icon)) {
|
||||
try {
|
||||
File iconDir = SpringXmlNamespacesPlugin.getDefault().getStateLocation().append("images").toFile();
|
||||
if (!iconDir.exists()) {
|
||||
iconDir.mkdirs();
|
||||
iconDir.deleteOnExit();
|
||||
}
|
||||
|
||||
int ix = icon.lastIndexOf('.');
|
||||
File iconFile = null;
|
||||
if (ix > 0) {
|
||||
iconFile = new File(iconDir, Integer.toString(namespaceUri.hashCode()) + icon.substring(ix));
|
||||
}
|
||||
else {
|
||||
iconFile = new File(iconDir, Integer.toString(namespaceUri.hashCode()));
|
||||
}
|
||||
|
||||
if (iconFile.exists()) {
|
||||
return iconFile;
|
||||
}
|
||||
|
||||
FileCopyUtils.copy(cls.getResourceAsStream(icon), new FileOutputStream(iconFile));
|
||||
return iconFile;
|
||||
}
|
||||
catch (Exception e) {
|
||||
SpringXmlNamespacesPlugin.log(
|
||||
String.format("Error extracting icon file '%s' for namespace '%s'", icon, namespaceUri), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the {@link EnablementPropertyChangeListener} listener to get notifications on changes to the project
|
||||
* preferences.
|
||||
*/
|
||||
private void registerListeners() {
|
||||
propertyChangeListener = new EnablementPropertyChangeListener();
|
||||
SpringXmlNamespacesPlugin.getDefault().getPluginPreferences().addPropertyChangeListener(propertyChangeListener);
|
||||
SpringCorePreferences.getProjectPreferences(project, SpringXmlNamespacesPlugin.PLUGIN_ID).getProjectPreferences()
|
||||
.addPreferenceChangeListener(propertyChangeListener);
|
||||
NamespaceManagerProvider.get().registerNamespaceDefinitionListener(propertyChangeListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister the {@link EnablementPropertyChangeListener}.
|
||||
*/
|
||||
private void unRegisterListeners() {
|
||||
SpringXmlNamespacesPlugin.getDefault().getPluginPreferences().removePropertyChangeListener(propertyChangeListener);
|
||||
SpringCorePreferences.getProjectPreferences(project, SpringXmlNamespacesPlugin.PLUGIN_ID).getProjectPreferences()
|
||||
.removePreferenceChangeListener(propertyChangeListener);
|
||||
NamespaceManagerProvider.get().unregisterNamespaceDefinitionListener(propertyChangeListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link IPropertyChangeListener} and {@link IPreferenceChangeListener} implementation that detects changes to the
|
||||
* classpath property.
|
||||
* @since 2.5.0
|
||||
*/
|
||||
private class EnablementPropertyChangeListener implements IPropertyChangeListener, IPreferenceChangeListener,
|
||||
INamespaceDefinitionListener {
|
||||
|
||||
private static final String KEY = SpringXmlNamespacesPlugin.PLUGIN_ID + "."
|
||||
+ SpringXmlNamespacesPlugin.LOAD_NAMESPACEHANDLER_FROM_CLASSPATH_ID;
|
||||
|
||||
private final String nodePath = "/project/" + project.getName() + "/" + SpringXmlNamespacesPlugin.PLUGIN_ID;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void preferenceChange(PreferenceChangeEvent event) {
|
||||
if (KEY.equals(event.getKey()) && nodePath.equals(event.getNode().absolutePath())) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) {
|
||||
if (SpringXmlNamespacesPlugin.LOAD_NAMESPACEHANDLER_FROM_CLASSPATH_ID.equals(event.getProperty())) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void onNamespaceDefinitionRegistered(NamespaceDefinitionChangeEvent event) {
|
||||
if (!XmlNamespaceUtils.useNamespacesFromClasspath(project)) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void onNamespaceDefinitionUnregistered(NamespaceDefinitionChangeEvent event) {
|
||||
if (!XmlNamespaceUtils.useNamespacesFromClasspath(project)) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension to {@link NamespaceDefinition} that handles loading of referenced namespace icons from extracted files.
|
||||
* @since 2.5.0
|
||||
*/
|
||||
private class ExternalImageNamespaceDefinition extends NamespaceDefinition {
|
||||
|
||||
private final File iconFile;
|
||||
|
||||
public ExternalImageNamespaceDefinition(Properties uriMapping, File iconFile) {
|
||||
super(uriMapping);
|
||||
this.iconFile = iconFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public InputStream getIconStream() {
|
||||
if (iconFile != null && iconFile.exists() && iconFile.canRead()) {
|
||||
try {
|
||||
return new FileInputStream(iconFile);
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Spring IDE Developers - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.jdt.core.ElementChangedEvent;
|
||||
import org.eclipse.jdt.core.IElementChangedListener;
|
||||
import org.eclipse.jdt.core.IJavaElementDelta;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.INamespaceDefinitionResolver;
|
||||
import org.springsource.ide.eclipse.commons.core.JdtUtils;
|
||||
|
||||
/**
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class ProjectClasspathNamespaceDefinitionResolverCache {
|
||||
|
||||
private static final int CACHE_SIZE = 12;
|
||||
|
||||
private static List<ResolvlerCacheEntry> RESOLVER_CACHE = new ArrayList<ResolvlerCacheEntry>(CACHE_SIZE);
|
||||
|
||||
private static INamespaceDefinitionResolver addResolverToCache(IProject project) {
|
||||
synchronized (RESOLVER_CACHE) {
|
||||
int nEntries = RESOLVER_CACHE.size();
|
||||
if (nEntries >= CACHE_SIZE) {
|
||||
// find obsolete entries or remove entry that was least recently accessed
|
||||
ResolvlerCacheEntry oldest = null;
|
||||
List<ResolvlerCacheEntry> obsoleteClassLoaders = new ArrayList<ResolvlerCacheEntry>(CACHE_SIZE);
|
||||
for (int i = 0; i < nEntries; i++) {
|
||||
ResolvlerCacheEntry entry = RESOLVER_CACHE.get(i);
|
||||
IProject curr = entry.getProject();
|
||||
if (!curr.exists() || !curr.isAccessible() || !curr.isOpen()) {
|
||||
obsoleteClassLoaders.add(entry);
|
||||
}
|
||||
else {
|
||||
if (oldest == null || entry.getLastAccess() < oldest.getLastAccess()) {
|
||||
oldest = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!obsoleteClassLoaders.isEmpty()) {
|
||||
for (int i = 0; i < obsoleteClassLoaders.size(); i++) {
|
||||
removeResolverEntryFromCache(obsoleteClassLoaders.get(i));
|
||||
}
|
||||
}
|
||||
else if (oldest != null) {
|
||||
removeResolverEntryFromCache(oldest);
|
||||
}
|
||||
}
|
||||
ResolvlerCacheEntry newEntry = new ResolvlerCacheEntry(project);
|
||||
RESOLVER_CACHE.add(newEntry);
|
||||
return newEntry.getResolver();
|
||||
}
|
||||
}
|
||||
|
||||
private static INamespaceDefinitionResolver findResolverInCache(IProject project) {
|
||||
synchronized (RESOLVER_CACHE) {
|
||||
for (int i = RESOLVER_CACHE.size() - 1; i >= 0; i--) {
|
||||
ResolvlerCacheEntry entry = RESOLVER_CACHE.get(i);
|
||||
IProject curr = entry.getProject();
|
||||
if (!curr.exists() || !curr.isAccessible() || !curr.isOpen()) {
|
||||
removeResolverEntryFromCache(entry);
|
||||
}
|
||||
else {
|
||||
if (entry.matches(project)) {
|
||||
entry.markAsAccessed();
|
||||
return entry.getResolver();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void removeResolverEntryFromCache(ResolvlerCacheEntry entry) {
|
||||
synchronized (RESOLVER_CACHE) {
|
||||
entry.dispose();
|
||||
RESOLVER_CACHE.remove(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static INamespaceDefinitionResolver getResolver(IProject project) {
|
||||
INamespaceDefinitionResolver resolver = findResolverInCache(project);
|
||||
if (resolver == null) {
|
||||
resolver = addResolverToCache(project);
|
||||
}
|
||||
return resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal cache entry
|
||||
*/
|
||||
private static class ResolvlerCacheEntry implements IElementChangedListener {
|
||||
|
||||
private long lastAccess;
|
||||
|
||||
private IProject project;
|
||||
|
||||
private ProjectClasspathNamespaceDefinitionResolver resolver;
|
||||
|
||||
public ResolvlerCacheEntry(IProject project) {
|
||||
this.project = project;
|
||||
this.resolver = new ProjectClasspathNamespaceDefinitionResolver(project);
|
||||
markAsAccessed();
|
||||
JavaCore.addElementChangedListener(this, ElementChangedEvent.POST_CHANGE);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
JavaCore.removeElementChangedListener(this);
|
||||
resolver.dispose();
|
||||
resolver = null;
|
||||
}
|
||||
|
||||
public void elementChanged(ElementChangedEvent event) {
|
||||
IJavaProject javaProject = JdtUtils.getJavaProject(project);
|
||||
if (javaProject != null) {
|
||||
for (IJavaElementDelta delta : event.getDelta().getAffectedChildren()) {
|
||||
if ((delta.getFlags() & IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED) != 0
|
||||
|| (delta.getFlags() & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0) {
|
||||
if (javaProject.equals(delta.getElement()) || javaProject.isOnClasspath(delta.getElement())) {
|
||||
removeResolverEntryFromCache(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public INamespaceDefinitionResolver getResolver() {
|
||||
return resolver;
|
||||
}
|
||||
|
||||
public long getLastAccess() {
|
||||
return lastAccess;
|
||||
}
|
||||
|
||||
public IProject getProject() {
|
||||
return this.project;
|
||||
}
|
||||
|
||||
public void markAsAccessed() {
|
||||
lastAccess = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean matches(IProject project) {
|
||||
return this.project.equals(project);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2011, 2019 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Spring IDE Developers - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.ProjectAwareUrlStreamHandlerService;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.SpringXmlNamespacesPlugin;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.XmlNamespaceUtils;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.classpath.ProjectResourceLoaderCache;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.classpath.PropertiesLoaderUtils;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.classpath.ResourceLoader;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.model.NamespaceDefinition;
|
||||
import org.springframework.ide.eclipse.xml.namespaces.util.TargetNamespaceScanner;
|
||||
import org.springsource.ide.eclipse.commons.core.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* resolves URIs on the project classpath using the protocol established by
|
||||
* <code>spring.schemas</code> files.
|
||||
*
|
||||
* @author Martin Lippert
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public class ProjectClasspathUriResolver {
|
||||
|
||||
private final IProject project;
|
||||
private boolean disableCaching;
|
||||
|
||||
private Map<String, String> typePublic;
|
||||
private Map<String, String> typeUri;
|
||||
private Map<String, String> schemaMappings;
|
||||
|
||||
public ProjectClasspathUriResolver(IProject project) {
|
||||
this.project = project;
|
||||
this.disableCaching = XmlNamespaceUtils
|
||||
.disableCachingForNamespaceLoadingFromClasspath(project);
|
||||
|
||||
if (!disableCaching) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given <code>systemId</code> on the classpath configured by
|
||||
* the <code>file</code>'s project.
|
||||
*/
|
||||
public String resolveOnClasspath(String publicId, String systemId) {
|
||||
if (disableCaching) {
|
||||
return resolveOnClasspathAndSourceFolders(publicId, systemId);
|
||||
}
|
||||
return resolveOnClasspathOnly(publicId, systemId);
|
||||
}
|
||||
|
||||
private String resolveOnClasspathAndSourceFolders(String publicId,
|
||||
String systemId) {
|
||||
ResourceLoader classLoader = ProjectResourceLoaderCache.getResourceLoader(project, null);
|
||||
Map<String, String> mappings = getSchemaMappings(classLoader);
|
||||
|
||||
if (mappings != null && systemId != null) {
|
||||
if (mappings.containsKey(systemId)) {
|
||||
String xsdPath = mappings.get(systemId);
|
||||
return resolveXsdPathOnClasspath(xsdPath, classLoader);
|
||||
}
|
||||
else if (mappings.containsKey(systemId.replace("https://", "http://"))) {
|
||||
String xsdPath = mappings.get(systemId.replace("https://", "http://"));
|
||||
return resolveXsdPathOnClasspath(xsdPath, classLoader);
|
||||
}
|
||||
else if (mappings.containsKey(systemId.replace("http://", "https://"))) {
|
||||
String xsdPath = mappings.get(systemId.replace("http://", "https://"));
|
||||
return resolveXsdPathOnClasspath(xsdPath, classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String resolveOnClasspathOnly(String publicId, String systemId) {
|
||||
String resolved = null;
|
||||
|
||||
if (systemId != null) {
|
||||
resolved = typeUri.get(systemId);
|
||||
}
|
||||
|
||||
if (resolved == null && systemId != null && systemId.startsWith("https://")) {
|
||||
resolved = typeUri.get(systemId.replace("https://", "http://"));
|
||||
}
|
||||
|
||||
if (resolved == null && systemId != null && systemId.startsWith("http://")) {
|
||||
resolved = typeUri.get(systemId.replace("http://", "https://"));
|
||||
}
|
||||
|
||||
if (resolved == null && publicId != null) {
|
||||
if (!(systemId != null && systemId.endsWith(".xsd"))) {
|
||||
resolved = typePublic.get(publicId);
|
||||
}
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
this.typePublic = new ConcurrentHashMap<String, String>();
|
||||
this.typeUri = new ConcurrentHashMap<String, String>();
|
||||
|
||||
Map<String, NamespaceDefinition> namespaceDefinitionRegistry = new HashMap<String, NamespaceDefinition>();
|
||||
ResourceLoader classLoader = ProjectResourceLoaderCache.getResourceLoader(project, null);
|
||||
|
||||
schemaMappings = getSchemaMappings(classLoader);
|
||||
if (schemaMappings != null) {
|
||||
for (String key : schemaMappings.keySet()) {
|
||||
String path = schemaMappings.get(key);
|
||||
|
||||
// add the resolved path to the list of uris
|
||||
String resolvedPath = resolveXsdPathOnClasspath(path,
|
||||
classLoader);
|
||||
if (resolvedPath != null) {
|
||||
typeUri.put(key, resolvedPath);
|
||||
|
||||
// collect base information to later extract the default uri
|
||||
String namespaceUri = getTargetNamespace(resolvedPath);
|
||||
|
||||
if (namespaceDefinitionRegistry.containsKey(namespaceUri)) {
|
||||
namespaceDefinitionRegistry.get(namespaceUri)
|
||||
.addSchemaLocation(key);
|
||||
namespaceDefinitionRegistry.get(namespaceUri).addUri(
|
||||
path);
|
||||
} else {
|
||||
NamespaceDefinition namespaceDefinition = new NamespaceDefinition(
|
||||
null);
|
||||
namespaceDefinition.addSchemaLocation(key);
|
||||
namespaceDefinition.setNamespaceUri(namespaceUri);
|
||||
namespaceDefinition.addUri(path);
|
||||
namespaceDefinitionRegistry.put(namespaceUri,
|
||||
namespaceDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add catalog entry to namespace uri
|
||||
for (NamespaceDefinition definition : namespaceDefinitionRegistry
|
||||
.values()) {
|
||||
String namespaceKey = definition.getNamespaceUri();
|
||||
String defaultUri = definition.getDefaultUri();
|
||||
|
||||
String resolvedPath = resolveXsdPathOnClasspath(defaultUri,
|
||||
classLoader);
|
||||
if (resolvedPath != null) {
|
||||
typePublic.put(namespaceKey, resolvedPath);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target namespace URI of the XSD identified by the given
|
||||
* <code>resolvedPath</code>.
|
||||
*/
|
||||
private String getTargetNamespace(String resolvedPath) {
|
||||
if (resolvedPath == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
URL url = new URI(
|
||||
ProjectAwareUrlStreamHandlerService.createProjectAwareUrl(
|
||||
project.getName(), resolvedPath)).toURL();
|
||||
return TargetNamespaceScanner.getTargetNamespace(url);
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
SpringXmlNamespacesPlugin.log(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all schema mappings from all <code>spring.schemas</code> files on
|
||||
* the project classpath.
|
||||
*
|
||||
* @param classLoader
|
||||
* The classloader that is used to load the properties
|
||||
*/
|
||||
private Map<String, String> getSchemaMappings(ResourceLoader classLoader) {
|
||||
Map<String, String> handlerMappings = new ConcurrentHashMap<String, String>();
|
||||
// try {
|
||||
Properties mappings = PropertiesLoaderUtils
|
||||
.loadAllProperties(
|
||||
ProjectClasspathNamespaceDefinitionResolver.DEFAULT_SCHEMA_MAPPINGS_LOCATION,
|
||||
classLoader);
|
||||
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
|
||||
// } catch (IOException ex) {
|
||||
// // We can ignore this as we simply don't find the xsd file then.
|
||||
// }
|
||||
return handlerMappings;
|
||||
}
|
||||
|
||||
private String resolveXsdPathOnClasspath(String xsdPath, ResourceLoader classLoader) {
|
||||
URL url = classLoader.getResource(xsdPath);
|
||||
|
||||
// fallback, if schema location starts with / and therefore fails to be
|
||||
// found by classloader
|
||||
if (url == null && xsdPath.startsWith("/")) {
|
||||
xsdPath = xsdPath.substring(1);
|
||||
url = classLoader.getResource(xsdPath);
|
||||
}
|
||||
|
||||
return url == null ? null : xsdPath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Spring IDE Developers - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.model;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a Spring namespace created from reading the <code>spring.tooling</code> file in
|
||||
* <code>META-INF</code>.
|
||||
* @author Christian Dupuis
|
||||
* @since 2.2.5
|
||||
*/
|
||||
public interface INamespaceDefinition {
|
||||
|
||||
/**
|
||||
* Returns the namespace prefix this namespace is associated with.
|
||||
*/
|
||||
String getPrefix();
|
||||
|
||||
/**
|
||||
* Returns the namepace name.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the InputStream to a namespace icon with the bundle.
|
||||
*/
|
||||
InputStream getIconStream();
|
||||
|
||||
/**
|
||||
* Returns a path to a namespace icon with the bundle.
|
||||
*/
|
||||
String getIconPath();
|
||||
|
||||
/**
|
||||
* Returns the namespace uri.
|
||||
*/
|
||||
String getNamespaceUri();
|
||||
|
||||
/**
|
||||
* Returns all available XSD schema locations.
|
||||
*/
|
||||
Set<String> getSchemaLocations();
|
||||
|
||||
/**
|
||||
* Returns the default schema location. By default this is the XSD with the highest version in
|
||||
* the file name.
|
||||
*/
|
||||
String getDefaultSchemaLocation();
|
||||
|
||||
/**
|
||||
* Return the url mappings
|
||||
*/
|
||||
Properties getUriMapping();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Spring IDE Developers - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.eclipse.xml.namespaces.model;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
|
||||
/**
|
||||
* Implementations of this interface will receive notifications when {@link INamespaceDefinition} are registered and
|
||||
* unregistered.
|
||||
* @author Christian Dupuis
|
||||
* @since 2.3.0
|
||||
*/
|
||||
public interface INamespaceDefinitionListener {
|
||||
|
||||
/**
|
||||
* Event notifying about a processed registration of a {@link INamespaceDefinition}.
|
||||
*/
|
||||
void onNamespaceDefinitionRegistered(NamespaceDefinitionChangeEvent event);
|
||||
|
||||
/**
|
||||
* Event notifying about a processed un-registration of a {@link INamespaceDefinition}.
|
||||
*/
|
||||
void onNamespaceDefinitionUnregistered(NamespaceDefinitionChangeEvent event);
|
||||
|
||||
class NamespaceDefinitionChangeEvent {
|
||||
|
||||
private final INamespaceDefinition namespaceDefinition;
|
||||
|
||||
private final IProject project;
|
||||
|
||||
public NamespaceDefinitionChangeEvent(INamespaceDefinition namespaceDefinition, IProject project) {
|
||||
this.namespaceDefinition = namespaceDefinition;
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public IProject getProject() {
|
||||
return this.project;
|
||||
}
|
||||
|
||||
public INamespaceDefinition getNamespaceDefinition() {
|
||||
return namespaceDefinition;
|
||||
}
|
||||
}
|
||||
}
|
||||