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 }