1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.osgi.extender.internal.support;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.osgi.framework.Bundle;
22 import org.osgi.framework.BundleContext;
23 import org.osgi.framework.ServiceRegistration;
24 import org.springframework.beans.factory.DisposableBean;
25 import org.springframework.beans.factory.InitializingBean;
26 import org.springframework.beans.factory.xml.NamespaceHandlerResolver;
27 import org.springframework.osgi.util.OsgiBundleUtils;
28 import org.springframework.osgi.util.OsgiServiceUtils;
29 import org.springframework.osgi.util.OsgiStringUtils;
30 import org.springframework.util.Assert;
31 import org.xml.sax.EntityResolver;
32
33 /**
34 * Support class that deals with namespace parsers discovered inside Spring
35 * bundles.
36 *
37 * @author Costin Leau
38 *
39 */
40 public class NamespaceManager implements InitializingBean, DisposableBean {
41
42 private static final Log log = LogFactory.getLog(NamespaceManager.class);
43
44 private static final String NS_HANDLER_RESOLVER_CLASS_NAME = NamespaceHandlerResolver.class.getName();
45
46 /**
47 * The set of all namespace plugins known to the extender
48 */
49 private NamespacePlugins namespacePlugins;
50
51 /**
52 * ServiceRegistration object returned by OSGi when registering the
53 * NamespacePlugins instance as a service
54 */
55 private ServiceRegistration nsResolverRegistration, enResolverRegistration = null;
56
57 /**
58 * OSGi Environment.
59 */
60 private final BundleContext context;
61
62 private final String extenderInfo;
63
64 private static final String META_INF = "META-INF/";
65
66 private static final String SPRING_HANDLERS = "spring.handlers";
67
68 private static final String SPRING_SCHEMAS = "spring.schemas";
69
70
71 /**
72 * Constructor.
73 *
74 * @param extenderBundleContext
75 */
76 public NamespaceManager(BundleContext context) {
77 this.context = context;
78
79 extenderInfo = context.getBundle().getSymbolicName() + "|"
80 + OsgiBundleUtils.getBundleVersion(context.getBundle());
81
82
83 this.namespacePlugins = new NamespacePlugins();
84 }
85
86 /**
87 * If this bundle defines handler mapping or schema mapping resources, then
88 * register it with the namespace plugin handler.
89 *
90 * <p/> This method considers only the bundle space and not the class space.
91 *
92 * @param bundle
93 */
94 public void maybeAddNamespaceHandlerFor(Bundle bundle) {
95
96 if (OsgiBundleUtils.isSystemBundle(bundle)) {
97 return;
98 }
99
100 boolean hasHandlers = bundle.findEntries(META_INF, SPRING_HANDLERS, false) != null;
101 boolean hasSchemas = bundle.findEntries(META_INF, SPRING_SCHEMAS, false) != null;
102
103
104 if (hasHandlers) {
105
106 if (hasCompatibleNamespaceType(bundle)) {
107 addHandler(bundle);
108 }
109 else {
110 if (log.isDebugEnabled())
111 log.debug("Bundle [" + OsgiStringUtils.nullSafeNameAndSymName(bundle)
112 + "] declares namespace handlers but is not compatible with extender [" + extenderInfo
113 + "]; ignoring...");
114 }
115
116 }
117 else {
118
119 if (hasSchemas)
120 addHandler(bundle);
121 }
122 }
123
124 private boolean hasCompatibleNamespaceType(Bundle bundle) {
125 try {
126 Class type = bundle.loadClass(NS_HANDLER_RESOLVER_CLASS_NAME);
127 return NamespaceHandlerResolver.class.equals(type);
128 }
129 catch (Throwable th) {
130
131 log.warn("Bundle " + OsgiStringUtils.nullSafeNameAndSymName(bundle) + " cannot see class ["
132 + NS_HANDLER_RESOLVER_CLASS_NAME + "]; ignoring its namespace handlers");
133
134 return false;
135 }
136 }
137
138 /**
139 * Add this bundle to those known to provide handler or schema mappings.
140 * This method expects that the validity check (whatever that is) has been
141 * already done.
142 *
143 * @param bundle
144 */
145 protected void addHandler(Bundle bundle) {
146 Assert.notNull(bundle);
147 if (log.isDebugEnabled()) {
148 log.debug("Adding namespace handler resolver for " + OsgiStringUtils.nullSafeNameAndSymName(bundle));
149 }
150
151 this.namespacePlugins.addHandler(bundle);
152 }
153
154 /**
155 * Remove this bundle from the set of those known to provide handler or
156 * schema mappings.
157 *
158 * @param bundle
159 */
160 public void maybeRemoveNameSpaceHandlerFor(Bundle bundle) {
161 Assert.notNull(bundle);
162 boolean removed = this.namespacePlugins.removeHandler(bundle);
163 if (removed && log.isDebugEnabled()) {
164 log.debug("Removed namespace handler resolver for " + OsgiStringUtils.nullSafeNameAndSymName(bundle));
165 }
166 }
167
168 /**
169 * Register the NamespacePlugins instance as an Osgi Resolver service
170 */
171 private void registerResolverServices() {
172 if (log.isDebugEnabled()) {
173 log.debug("Registering Spring NamespaceHandlerResolver and EntityResolver...");
174 }
175
176 nsResolverRegistration = context.registerService(new String[] { NamespaceHandlerResolver.class.getName() },
177 this.namespacePlugins, null);
178
179 enResolverRegistration = context.registerService(new String[] { EntityResolver.class.getName() },
180 this.namespacePlugins, null);
181
182 }
183
184 /**
185 * Unregister the NamespaceHandler and EntityResolver service
186 */
187 private void unregisterResolverService() {
188
189 boolean result = OsgiServiceUtils.unregisterService(nsResolverRegistration);
190 result = result || OsgiServiceUtils.unregisterService(enResolverRegistration);
191
192 if (result) {
193 if (log.isDebugEnabled())
194 log.debug("Unregistering Spring NamespaceHandler and EntityResolver service");
195 }
196
197 this.nsResolverRegistration = null;
198 this.enResolverRegistration = null;
199 }
200
201 /**
202 * @return Returns the namespacePlugins.
203 */
204 public NamespacePlugins getNamespacePlugins() {
205 return namespacePlugins;
206 }
207
208
209
210
211
212 public void afterPropertiesSet() {
213 registerResolverServices();
214 }
215
216 public void destroy() {
217 unregisterResolverService();
218 this.namespacePlugins.destroy();
219 this.namespacePlugins = null;
220 }
221
222 }