1 /*******************************************************************************
2 * Copyright (c) 2014, 2015 Obeo.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * Obeo - initial API and implementation
10 *******************************************************************************/
11 package org
.eclipse
.emf
.compare
.ide
.internal
.utils
;
14 import java
.util
.StringTokenizer
;
16 import org
.eclipse
.core
.runtime
.ListenerList
;
17 import org
.eclipse
.emf
.common
.util
.URI
;
18 import org
.eclipse
.emf
.ecore
.EObject
;
19 import org
.eclipse
.emf
.ecore
.EReference
;
20 import org
.eclipse
.emf
.ecore
.EStructuralFeature
;
21 import org
.eclipse
.emf
.ecore
.util
.ExtendedMetaData
;
22 import org
.eclipse
.emf
.ecore
.xmi
.XMLDefaultHandler
;
23 import org
.eclipse
.emf
.ecore
.xmi
.XMLHelper
;
24 import org
.eclipse
.emf
.ecore
.xmi
.XMLLoad
;
25 import org
.eclipse
.emf
.ecore
.xmi
.XMLResource
;
26 import org
.eclipse
.emf
.ecore
.xmi
.impl
.XMLParserPoolImpl
;
27 import org
.xml
.sax
.Attributes
;
28 import org
.xml
.sax
.SAXException
;
31 * This implementation of an XML parser pool will notify a list of {@link INamespaceDeclarationListener
32 * namespace declaration listeners} of all namespaces declared in the parsed resource (xsi:schemalocation),
33 * then a list of {@link IProxyCreationListener proxy creation listeners} of each and every proxy it sees
34 * while loading an XML file as an EMF model.
36 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
38 public class NotifyingParserPool
extends XMLParserPoolImpl
{
39 /** Only set containment reference values, ignore the rest. */
40 protected final boolean containmentOnly
;
42 /** The list of parties interested by our proxies. */
43 private ListenerList proxyListeners
;
45 /** The list of parties interested in the declaration of namespaces. */
46 private ListenerList namespaceDeclarationListeners
;
49 * Default constructor.
51 * @param containmentOnly
52 * only set containment reference values. The model will be mostly empty except for its
55 public NotifyingParserPool(boolean containmentOnly
) {
57 this.proxyListeners
= new ListenerList();
58 this.namespaceDeclarationListeners
= new ListenerList();
59 this.containmentOnly
= containmentOnly
;
64 public synchronized XMLDefaultHandler
getDefaultHandler(XMLResource resource
, XMLLoad xmlLoad
,
65 XMLHelper helper
, Map
<?
, ?
> options
) {
66 final NotifyingXMLHelper wrapper
= new NotifyingXMLHelper(helper
, containmentOnly
);
67 for (Object listener
: proxyListeners
.getListeners()) {
68 wrapper
.addProxyListener((IProxyCreationListener
)listener
);
70 final XMLDefaultHandler handler
= createDefaultHandler(resource
, xmlLoad
, wrapper
, options
);
71 final NamespaceDeclarationNotifyingXMLDefaultHandler handlerWrapper
= new NamespaceDeclarationNotifyingXMLDefaultHandler(
73 for (Object listener
: namespaceDeclarationListeners
.getListeners()) {
74 handlerWrapper
.addNamespaceDeclarationListener((INamespaceDeclarationListener
)listener
);
76 handlerWrapper
.prepare(resource
, wrapper
, options
);
77 return handlerWrapper
;
81 * Create the default (unwrapped) XMLDefaultHandler. This is merely a call to <code>super</code> but can
85 * The resource to load.
87 * The XML load to pass on tho the handler.
89 * The XML helper to pass on tho the handler.
91 * The load options for this resource.
92 * @return The created XMLDefaultHandler.
93 * @see #getDefaultHandler(XMLResource, XMLLoad, XMLHelper, Map)
95 protected XMLDefaultHandler
createDefaultHandler(XMLResource resource
, XMLLoad xmlLoad
, XMLHelper helper
,
97 return super.getDefaultHandler(resource
, xmlLoad
, helper
, options
);
101 * Add a proxy creation listener to this parser pool's list.
104 * The listener to add to this pool's list.
106 public void addProxyListener(IProxyCreationListener listener
) {
107 proxyListeners
.add(listener
);
111 * Remove a proxy creation listener from this parser pool's list.
114 * The listener to remove from this pool's list.
116 public void removeProxyListener(IProxyCreationListener listener
) {
117 proxyListeners
.remove(listener
);
121 * Add a namespace declaration listener to this parser pool's list.
124 * The listener to add to this pool's list.
126 public void addNamespaceDeclarationListener(INamespaceDeclarationListener listener
) {
127 namespaceDeclarationListeners
.add(listener
);
131 * Remove a namespace declaration listener from this parser pool's list.
134 * The listener to remove from this pool's list.
136 public void removeNamespaceDeclarationListener(INamespaceDeclarationListener listener
) {
137 namespaceDeclarationListeners
.remove(listener
);
141 * An XMLDefaultHandler that will notify interested {@link INamespaceDeclarationListener listeners} of its
142 * namespace declarations.
144 private static class NamespaceDeclarationNotifyingXMLDefaultHandler
extends ForwardingXMLDefaultHandler
{
145 /** The list of parties interested in the declaration of namespaces. */
146 private ListenerList namespaceDeclarationListeners
;
148 /** <code>true</code> only when we're parsing the very first element. */
149 private boolean isRoot
;
152 * Constructs a wrapper given its delegate.
155 * The delegate handler.
157 public NamespaceDeclarationNotifyingXMLDefaultHandler(XMLDefaultHandler delegate
) {
159 this.namespaceDeclarationListeners
= new ListenerList();
163 public void startDocument() throws SAXException
{
165 super.startDocument();
169 public void startElement(String arg0
, String arg1
, String arg2
, Attributes arg3
) throws SAXException
{
171 String xsiSchemaLocation
= arg3
.getValue(ExtendedMetaData
.XSI_URI
,
172 XMLResource
.SCHEMA_LOCATION
);
173 if (xsiSchemaLocation
!= null) {
174 declareSchemaLocation(xsiSchemaLocation
);
178 super.startElement(arg0
, arg1
, arg2
, arg3
);
182 * Add a namespace declaration listener to this helper's list.
185 * The listener to add to this helper's list.
187 public void addNamespaceDeclarationListener(INamespaceDeclarationListener listener
) {
188 namespaceDeclarationListeners
.add(listener
);
192 * We've read the headers of the resource to load. Notify our {@link #namespaceDeclarationListeners
193 * listeners} about the schema locations that can be found therein.
195 * @param xsiSchemaLocation
196 * The String of xsi:schemalocation declarations in the file.
198 private void declareSchemaLocation(String xsiSchemaLocation
) {
199 StringTokenizer stringTokenizer
= new StringTokenizer(xsiSchemaLocation
, " "); //$NON-NLS-1$
200 while (stringTokenizer
.hasMoreTokens()) {
201 String key
= stringTokenizer
.nextToken();
202 if (stringTokenizer
.hasMoreTokens()) {
203 String value
= stringTokenizer
.nextToken();
204 URI uri
= URI
.createURI(value
);
205 for (Object listener
: namespaceDeclarationListeners
.getListeners()) {
206 ((INamespaceDeclarationListener
)listener
).schemaLocationDeclared(key
, uri
);
214 * An XMLHelper wrapper that's capable of notifying {@link IProxyCreationListener listeners}s about proxy
217 private static class NotifyingXMLHelper
extends ForwardingXMLHelper
{
218 /** The list of parties interested by our proxy creations. */
219 private final ListenerList proxyListeners
;
221 /** Only set containment reference values, ignore the rest. */
222 private final boolean containmentOnly
;
225 * Constructs a wrapper given its delegate XMLHelper.
228 * The delegate XMLHelper.
229 * @param containmentOnly
230 * Only set containment reference values.
232 public NotifyingXMLHelper(XMLHelper delegate
, boolean containmentOnly
) {
234 this.proxyListeners
= new ListenerList();
235 this.containmentOnly
= containmentOnly
;
240 public void setValue(EObject eObject
, EStructuralFeature eStructuralFeature
, Object value
,
243 || (eStructuralFeature
instanceof EReference
&& ((EReference
)eStructuralFeature
)
245 super.setValue(eObject
, eStructuralFeature
, value
, position
);
247 if (value
instanceof EObject
&& ((EObject
)value
).eIsProxy()) {
248 for (Object listener
: proxyListeners
.getListeners()) {
249 ((IProxyCreationListener
)listener
).proxyCreated(getResource(), eObject
,
250 eStructuralFeature
, (EObject
)value
, position
);
256 * Add a proxy creation listener to this helper's list.
259 * The listener to add to this helper's list.
261 public void addProxyListener(IProxyCreationListener listener
) {
262 proxyListeners
.add(listener
);