001 /*
002 * JBoss DNA (http://www.jboss.org/dna)
003 * See the COPYRIGHT.txt file distributed with this work for information
004 * regarding copyright ownership. Some portions may be licensed
005 * to Red Hat, Inc. under one or more contributor license agreements.
006 * See the AUTHORS.txt file in the distribution for a full listing of
007 * individual contributors.
008 *
009 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010 * is licensed to you under the terms of the GNU Lesser General Public License as
011 * published by the Free Software Foundation; either version 2.1 of
012 * the License, or (at your option) any later version.
013 *
014 * JBoss DNA is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017 * Lesser General Public License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this software; if not, write to the Free
021 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023 */
024 package org.jboss.dna.graph;
025
026 import java.security.AccessControlContext;
027 import java.security.AccessController;
028 import javax.security.auth.login.LoginException;
029 import net.jcip.annotations.Immutable;
030 import org.jboss.dna.common.component.ClassLoaderFactory;
031 import org.jboss.dna.common.component.StandardClassLoaderFactory;
032 import org.jboss.dna.common.util.CheckArg;
033 import org.jboss.dna.common.util.Logger;
034 import org.jboss.dna.graph.mimetype.ExtensionBasedMimeTypeDetector;
035 import org.jboss.dna.graph.mimetype.MimeTypeDetector;
036 import org.jboss.dna.graph.property.NamespaceRegistry;
037 import org.jboss.dna.graph.property.Property;
038 import org.jboss.dna.graph.property.PropertyFactory;
039 import org.jboss.dna.graph.property.ValueFactories;
040 import org.jboss.dna.graph.property.basic.BasicPropertyFactory;
041 import org.jboss.dna.graph.property.basic.SimpleNamespaceRegistry;
042 import org.jboss.dna.graph.property.basic.StandardValueFactories;
043 import org.jboss.dna.graph.property.basic.ThreadSafeNamespaceRegistry;
044
045 /**
046 * An ExecutionContext is a representation of the environment or context in which a component or operation is operating. Some
047 * components require this context to be passed into individual methods, allowing the context to vary with each method invocation.
048 * Other components require the context to be provided before it's used, and will use that context for all its operations (until
049 * it is given a different one).
050 * <p>
051 * ExecutionContext instances are {@link Immutable immutable}, so components may hold onto references to them without concern of
052 * those contexts changing. Contexts may be used to create other contexts that vary the environment and/or security context. For
053 * example, an ExecutionContext could be used to create another context that references the same {@link #getNamespaceRegistry()
054 * namespace registry} but which has a different {@link #getSecurityContext() security context}.
055 * </p>
056 *
057 * @author Randall Hauch
058 * @author John Verhaeg
059 */
060 @Immutable
061 public class ExecutionContext implements ClassLoaderFactory, Cloneable {
062
063 private final ClassLoaderFactory classLoaderFactory;
064 private final PropertyFactory propertyFactory;
065 private final ValueFactories valueFactories;
066 private final NamespaceRegistry namespaceRegistry;
067 private final MimeTypeDetector mimeTypeDetector;
068 private final SecurityContext securityContext;
069
070 /**
071 * Create an instance of an execution context that uses the {@link AccessController#getContext() current JAAS calling context}
072 * , with default implementations for all other components (including default namespaces in the
073 * {@link #getNamespaceRegistry() namespace registry}.
074 */
075 @SuppressWarnings( "synthetic-access" )
076 public ExecutionContext() {
077 this(new NullSecurityContext(), null, null, null, null, null);
078 initializeDefaultNamespaces(this.getNamespaceRegistry());
079 assert securityContext != null;
080
081 }
082
083 /**
084 * Create a copy of the supplied execution context.
085 *
086 * @param original the original
087 * @throws IllegalArgumentException if the original is null
088 */
089 protected ExecutionContext( ExecutionContext original ) {
090 CheckArg.isNotNull(original, "original");
091 this.securityContext = original.getSecurityContext();
092 this.namespaceRegistry = original.getNamespaceRegistry();
093 this.valueFactories = original.getValueFactories();
094 this.propertyFactory = original.getPropertyFactory();
095 this.classLoaderFactory = original.getClassLoaderFactory();
096 this.mimeTypeDetector = original.getMimeTypeDetector();
097 }
098
099 /**
100 * Create a copy of the supplied execution context, but use the supplied {@link AccessControlContext} instead.
101 *
102 * @param original the original
103 * @param securityContext the security context
104 * @throws IllegalArgumentException if the original or access control context are is null
105 */
106 protected ExecutionContext( ExecutionContext original,
107 SecurityContext securityContext ) {
108 CheckArg.isNotNull(original, "original");
109 CheckArg.isNotNull(securityContext, "securityContext");
110 this.securityContext = securityContext;
111 this.namespaceRegistry = original.getNamespaceRegistry();
112 this.valueFactories = original.getValueFactories();
113 this.propertyFactory = original.getPropertyFactory();
114 this.classLoaderFactory = original.getClassLoaderFactory();
115 this.mimeTypeDetector = original.getMimeTypeDetector();
116 }
117
118 /**
119 * Create an instance of the execution context by supplying all parameters.
120 *
121 * @param securityContext the security context, or null if there is no associated authenticated user
122 * @param namespaceRegistry the namespace registry implementation, or null if a thread-safe version of
123 * {@link SimpleNamespaceRegistry} instance should be used
124 * @param valueFactories the {@link ValueFactories} implementation, or null if a {@link StandardValueFactories} instance
125 * should be used
126 * @param propertyFactory the {@link PropertyFactory} implementation, or null if a {@link BasicPropertyFactory} instance
127 * should be used
128 * @param mimeTypeDetector the {@link MimeTypeDetector} implementation, or null if an {@link ExtensionBasedMimeTypeDetector}
129 * instance should be used
130 * @param classLoaderFactory the {@link ClassLoaderFactory} implementation, or null if a {@link StandardClassLoaderFactory}
131 * instance should be used
132 */
133 protected ExecutionContext( SecurityContext securityContext,
134 NamespaceRegistry namespaceRegistry,
135 ValueFactories valueFactories,
136 PropertyFactory propertyFactory,
137 MimeTypeDetector mimeTypeDetector,
138 ClassLoaderFactory classLoaderFactory ) {
139 assert securityContext != null;
140 this.securityContext = securityContext;
141 this.namespaceRegistry = namespaceRegistry != null ? namespaceRegistry : new ThreadSafeNamespaceRegistry(
142 new SimpleNamespaceRegistry());
143 this.valueFactories = valueFactories == null ? new StandardValueFactories(this.namespaceRegistry) : valueFactories;
144 this.propertyFactory = propertyFactory == null ? new BasicPropertyFactory(this.valueFactories) : propertyFactory;
145 this.classLoaderFactory = classLoaderFactory == null ? new StandardClassLoaderFactory() : classLoaderFactory;
146 this.mimeTypeDetector = mimeTypeDetector != null ? mimeTypeDetector : new ExtensionBasedMimeTypeDetector();
147 }
148
149 /**
150 * Get the class loader factory used by this context.
151 *
152 * @return the class loader factory implementation; never null
153 */
154 protected ClassLoaderFactory getClassLoaderFactory() {
155 return classLoaderFactory;
156 }
157
158 /**
159 * Return a logger associated with this context. This logger records only those activities within the context and provide a
160 * way to capture the context-specific activities. All log messages are also sent to the system logger, so classes that log
161 * via this mechanism should <i>not</i> also {@link Logger#getLogger(Class) obtain a system logger}.
162 *
163 * @param clazz the class that is doing the logging
164 * @return the logger, named after <code>clazz</code>; never null
165 * @see #getLogger(String)
166 */
167 public Logger getLogger( Class<?> clazz ) {
168 return Logger.getLogger(clazz);
169 }
170
171 /**
172 * Return a logger associated with this context. This logger records only those activities within the context and provide a
173 * way to capture the context-specific activities. All log messages are also sent to the system logger, so classes that log
174 * via this mechanism should <i>not</i> also {@link Logger#getLogger(Class) obtain a system logger}.
175 *
176 * @param name the name for the logger
177 * @return the logger, named after <code>clazz</code>; never null
178 * @see #getLogger(Class)
179 */
180 public Logger getLogger( String name ) {
181 return Logger.getLogger(name);
182 }
183
184 /**
185 * Return an object that can be used to determine the MIME type of some content, such as the content of a file.
186 *
187 * @return the detector; never null
188 */
189 public MimeTypeDetector getMimeTypeDetector() {
190 return this.mimeTypeDetector;
191 }
192
193 /**
194 * Get the {@link SecurityContext security context} for this context.
195 *
196 * @return the security context; never <code>null</code>
197 */
198 public SecurityContext getSecurityContext() {
199 return this.securityContext;
200 }
201
202 /**
203 * Get the (mutable) namespace registry for this context.
204 *
205 * @return the namespace registry; never <code>null</code>
206 */
207 public NamespaceRegistry getNamespaceRegistry() {
208 return this.namespaceRegistry;
209 }
210
211 /**
212 * Get the factory for creating {@link Property} objects.
213 *
214 * @return the property factory; never <code>null</code>
215 */
216 public PropertyFactory getPropertyFactory() {
217 return this.propertyFactory;
218 }
219
220 /**
221 * Get the factories that should be used to create values for {@link Property properties}.
222 *
223 * @return the property value factory; never null
224 */
225 public ValueFactories getValueFactories() {
226 return this.valueFactories;
227 }
228
229 /**
230 * {@inheritDoc}
231 *
232 * @see org.jboss.dna.common.component.ClassLoaderFactory#getClassLoader(java.lang.String[])
233 */
234 public ClassLoader getClassLoader( String... classpath ) {
235 return this.classLoaderFactory.getClassLoader(classpath);
236 }
237
238 /**
239 * Create a new execution context that mirrors this context but that uses the supplied namespace registry. The resulting
240 * context's {@link #getValueFactories() value factories} and {@link #getPropertyFactory() property factory} all make use of
241 * the new namespace registry.
242 *
243 * @param namespaceRegistry the new namespace registry implementation, or null if the default implementation should be used
244 * @return the execution context that is identical with this execution context, but which uses the supplied registry; never
245 * null
246 */
247 public ExecutionContext with( NamespaceRegistry namespaceRegistry ) {
248 // Don't supply the value factories or property factories, since they'll have to be recreated
249 // to reference the supplied namespace registry ...
250 return new ExecutionContext(this.getSecurityContext(), namespaceRegistry, null, null, this.getMimeTypeDetector(),
251 this.getClassLoaderFactory());
252 }
253
254 /**
255 * Create a new execution context that is the same as this context, but which uses the supplied {@link MimeTypeDetector MIME
256 * type detector}.
257 *
258 * @param mimeTypeDetector the new MIME type detector implementation, or null if the default implementation should be used
259 * @return the execution context that is identical with this execution context, but which uses the supplied detector
260 * implementation; never null
261 */
262 public ExecutionContext with( MimeTypeDetector mimeTypeDetector ) {
263 // Don't supply the value factories or property factories, since they'll have to be recreated
264 // to reference the supplied namespace registry ...
265 return new ExecutionContext(this.getSecurityContext(), getNamespaceRegistry(), getValueFactories(), getPropertyFactory(),
266 mimeTypeDetector, getClassLoaderFactory());
267 }
268
269 /**
270 * Create a new execution context that mirrors this context but that uses the supplied {@link ClassLoaderFactory class loader
271 * factory}.
272 *
273 * @param classLoaderFactory the new class loader factory implementation, or null if the default implementation should be used
274 * @return the execution context that is identical with this execution context, but which uses the supplied class loader
275 * factory implementation; never null
276 */
277 public ExecutionContext with( ClassLoaderFactory classLoaderFactory ) {
278 // Don't supply the value factories or property factories, since they'll have to be recreated
279 // to reference the supplied namespace registry ...
280 return new ExecutionContext(this.getSecurityContext(), getNamespaceRegistry(), getValueFactories(), getPropertyFactory(),
281 getMimeTypeDetector(), classLoaderFactory);
282 }
283
284 /**
285 * Create an {@link ExecutionContext} that is the same as this context, but which uses the supplied {@link SecurityContext
286 * security context}.
287 *
288 * @param securityContext the new security context to use; may be null
289 * @return the execution context that is identical with this execution context, but with a different security context; never
290 * null
291 * @throws IllegalArgumentException if the <code>name</code> is null
292 * @throws LoginException if there <code>name</code> is invalid (or there is no login context named "other"), or if the
293 * default callback handler JAAS property was not set or could not be loaded
294 */
295 public ExecutionContext with( SecurityContext securityContext ) throws LoginException {
296 return new ExecutionContext(this, securityContext);
297 }
298
299 /**
300 * {@inheritDoc}
301 *
302 * @see java.lang.Object#clone()
303 */
304 @Override
305 public ExecutionContext clone() {
306 return new ExecutionContext(this);
307 }
308
309 /**
310 * {@inheritDoc}
311 *
312 * @see java.lang.Object#toString()
313 */
314 @Override
315 public String toString() {
316 return "Execution context for " + getSecurityContext() == null ? "null" : getSecurityContext().getUserName();
317 }
318
319 /**
320 * Method that initializes the default namespaces for namespace registries.
321 *
322 * @param namespaceRegistry the namespace registry
323 */
324 protected void initializeDefaultNamespaces( NamespaceRegistry namespaceRegistry ) {
325 if (namespaceRegistry == null) return;
326 namespaceRegistry.register(JcrLexicon.Namespace.PREFIX, JcrLexicon.Namespace.URI);
327 namespaceRegistry.register(JcrMixLexicon.Namespace.PREFIX, JcrMixLexicon.Namespace.URI);
328 namespaceRegistry.register(JcrNtLexicon.Namespace.PREFIX, JcrNtLexicon.Namespace.URI);
329 namespaceRegistry.register(DnaLexicon.Namespace.PREFIX, DnaLexicon.Namespace.URI);
330 // namespaceRegistry.register("dnadtd", "http://www.jboss.org/dna/dtd/1.0");
331 // namespaceRegistry.register("dnaxml", "http://www.jboss.org/dna/xml/1.0");
332 }
333
334 /**
335 * Default security context that confers no roles.
336 */
337 private static class NullSecurityContext implements SecurityContext {
338
339 public String getUserName() {
340 return null;
341 }
342
343 public boolean hasRole( String roleName ) {
344 return false;
345 }
346
347 public void logout() {
348 }
349
350 }
351 }