001 /* 002 * JBoss, Home of Professional Open Source. 003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors 004 * as indicated by the @author tags. See the copyright.txt file in the 005 * distribution for a full listing of individual contributors. 006 * 007 * This is free software; you can redistribute it and/or modify it 008 * under the terms of the GNU Lesser General Public License as 009 * published by the Free Software Foundation; either version 2.1 of 010 * the License, or (at your option) any later version. 011 * 012 * This software is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this software; if not, write to the Free 019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 021 */ 022 package org.jboss.dna.repository.sequencers; 023 024 import java.io.IOException; 025 import java.io.InputStream; 026 import java.security.AccessControlContext; 027 import java.util.Collections; 028 import java.util.HashSet; 029 import java.util.Set; 030 import javax.jcr.Node; 031 import javax.jcr.PropertyIterator; 032 import javax.jcr.PropertyType; 033 import javax.jcr.RepositoryException; 034 import javax.jcr.Value; 035 import javax.security.auth.Subject; 036 import javax.security.auth.login.LoginContext; 037 import net.jcip.annotations.Immutable; 038 import org.jboss.dna.common.collection.Problems; 039 import org.jboss.dna.common.util.CheckArg; 040 import org.jboss.dna.common.util.Logger; 041 import org.jboss.dna.graph.properties.Name; 042 import org.jboss.dna.graph.properties.NamespaceRegistry; 043 import org.jboss.dna.graph.properties.Path; 044 import org.jboss.dna.graph.properties.Property; 045 import org.jboss.dna.graph.properties.PropertyFactory; 046 import org.jboss.dna.graph.properties.ValueFactories; 047 import org.jboss.dna.graph.sequencers.SequencerContext; 048 import org.jboss.dna.graph.sequencers.StreamSequencer; 049 import org.jboss.dna.repository.RepositoryI18n; 050 import org.jboss.dna.repository.mimetype.MimeType; 051 import org.jboss.dna.repository.util.JcrExecutionContext; 052 053 /** 054 * Contains context information that is passed to {@link StreamSequencer stream sequencers}, including information about the input 055 * node containing the data being sequenced. 056 * 057 * @author John Verhaeg 058 */ 059 @Immutable 060 public class SequencerNodeContext implements SequencerContext { 061 062 private final javax.jcr.Property sequencedProperty; 063 private final ValueFactories factories; 064 private final Path path; 065 private final Set<Property> props; 066 private final JcrExecutionContext context; 067 private final Problems problems; 068 069 SequencerNodeContext( Node input, 070 javax.jcr.Property sequencedProperty, 071 JcrExecutionContext context, 072 Problems problems ) throws RepositoryException { 073 assert input != null; 074 assert sequencedProperty != null; 075 assert context != null; 076 assert problems != null; 077 this.context = context; 078 this.sequencedProperty = sequencedProperty; 079 this.problems = problems; 080 this.factories = context.getValueFactories(); 081 // Translate JCR path and property values to DNA constructs and cache them to improve performance and prevent 082 // RepositoryException from being thrown by getters 083 // Note: getMimeType() will still operate lazily, and thus throw a SequencerException, since it is very intrusive and 084 // potentially slow-running. 085 path = factories.getPathFactory().create(input.getPath()); 086 Set<Property> props = new HashSet<Property>(); 087 for (PropertyIterator iter = input.getProperties(); iter.hasNext();) { 088 javax.jcr.Property jcrProp = iter.nextProperty(); 089 Property prop; 090 if (jcrProp.getDefinition().isMultiple()) { 091 Value[] jcrVals = jcrProp.getValues(); 092 Object[] vals = new Object[jcrVals.length]; 093 int ndx = 0; 094 for (Value jcrVal : jcrVals) { 095 vals[ndx++] = convert(factories, jcrProp.getName(), jcrVal); 096 } 097 prop = context.getPropertyFactory().create(factories.getNameFactory().create(jcrProp.getName()), vals); 098 } else { 099 Value jcrVal = jcrProp.getValue(); 100 Object val = convert(factories, jcrProp.getName(), jcrVal); 101 prop = context.getPropertyFactory().create(factories.getNameFactory().create(jcrProp.getName()), val); 102 } 103 props.add(prop); 104 } 105 this.props = Collections.unmodifiableSet(props); 106 } 107 108 private Object convert( ValueFactories factories, 109 String name, 110 Value jcrValue ) throws RepositoryException { 111 switch (jcrValue.getType()) { 112 case PropertyType.BINARY: { 113 return factories.getBinaryFactory().create(jcrValue.getStream()); 114 } 115 case PropertyType.BOOLEAN: { 116 return factories.getBooleanFactory().create(jcrValue.getBoolean()); 117 } 118 case PropertyType.DATE: { 119 return factories.getDateFactory().create(jcrValue.getDate()); 120 } 121 case PropertyType.DOUBLE: { 122 return factories.getDoubleFactory().create(jcrValue.getDouble()); 123 } 124 case PropertyType.LONG: { 125 return factories.getLongFactory().create(jcrValue.getLong()); 126 } 127 case PropertyType.NAME: { 128 return factories.getNameFactory().create(jcrValue.getString()); 129 } 130 case PropertyType.PATH: { 131 return factories.getPathFactory().create(jcrValue.getString()); 132 } 133 case PropertyType.REFERENCE: { 134 return factories.getReferenceFactory().create(jcrValue.getString()); 135 } 136 case PropertyType.STRING: { 137 return factories.getStringFactory().create(jcrValue.getString()); 138 } 139 default: { 140 throw new RepositoryException(RepositoryI18n.unknownPropertyValueType.text(name, jcrValue.getType())); 141 } 142 } 143 } 144 145 /** 146 * {@inheritDoc} 147 * 148 * @see org.jboss.dna.graph.ExecutionContext#getAccessControlContext() 149 */ 150 public AccessControlContext getAccessControlContext() { 151 return context.getAccessControlContext(); 152 } 153 154 /** 155 * {@inheritDoc} 156 * 157 * @see org.jboss.dna.common.component.ClassLoaderFactory#getClassLoader(java.lang.String[]) 158 */ 159 public ClassLoader getClassLoader( String... classpath ) { 160 return context.getClassLoader(classpath); 161 } 162 163 /** 164 * {@inheritDoc} 165 */ 166 public ValueFactories getValueFactories() { 167 return factories; 168 } 169 170 /** 171 * {@inheritDoc} 172 * 173 * @see org.jboss.dna.graph.sequencers.SequencerContext#getInputPath() 174 */ 175 public Path getInputPath() { 176 return path; 177 } 178 179 /** 180 * {@inheritDoc} 181 * 182 * @see org.jboss.dna.graph.sequencers.SequencerContext#getInputProperties() 183 */ 184 public Set<Property> getInputProperties() { 185 return props; 186 } 187 188 /** 189 * {@inheritDoc} 190 * 191 * @see org.jboss.dna.graph.sequencers.SequencerContext#getInputProperty(org.jboss.dna.graph.properties.Name) 192 */ 193 public Property getInputProperty( Name name ) { 194 CheckArg.isNotNull(name, "name"); 195 for (Property prop : props) { 196 if (name.equals(prop.getName())) { 197 return prop; 198 } 199 } 200 return null; 201 } 202 203 /** 204 * {@inheritDoc} 205 * 206 * @see org.jboss.dna.graph.sequencers.SequencerContext#getProblems() 207 */ 208 public Problems getProblems() { 209 return problems; 210 } 211 212 /** 213 * {@inheritDoc} 214 * 215 * @see org.jboss.dna.graph.sequencers.SequencerContext#getMimeType() 216 */ 217 @SuppressWarnings( "null" ) 218 // The need for the SuppressWarnings looks like an Eclipse bug 219 public String getMimeType() { 220 SequencerException err = null; 221 String mimeType = null; 222 InputStream stream = null; 223 try { 224 stream = sequencedProperty.getStream(); 225 mimeType = MimeType.of(path.getLastSegment().getName().getLocalName(), stream); 226 return mimeType; 227 } catch (Exception error) { 228 err = new SequencerException(error); 229 } finally { 230 if (stream != null) { 231 try { 232 stream.close(); 233 } catch (IOException error) { 234 // Only throw exception if an exception was not already thrown 235 if (err == null) err = new SequencerException(error); 236 } 237 } 238 } 239 if (err != null) throw err; 240 return mimeType; 241 } 242 243 /** 244 * {@inheritDoc} 245 * 246 * @see org.jboss.dna.graph.sequencers.SequencerContext#getLogger(java.lang.Class) 247 */ 248 public Logger getLogger( Class<?> clazz ) { 249 return context.getLogger(clazz); 250 } 251 252 /** 253 * {@inheritDoc} 254 * 255 * @see org.jboss.dna.graph.sequencers.SequencerContext#getLogger(java.lang.String) 256 */ 257 public Logger getLogger( String name ) { 258 return context.getLogger(name); 259 } 260 261 /** 262 * {@inheritDoc} 263 * 264 * @see org.jboss.dna.graph.ExecutionContext#getLoginContext() 265 */ 266 public LoginContext getLoginContext() { 267 return context.getLoginContext(); 268 } 269 270 /** 271 * {@inheritDoc} 272 */ 273 public NamespaceRegistry getNamespaceRegistry() { 274 return factories.getNameFactory().getNamespaceRegistry(); 275 } 276 277 /** 278 * {@inheritDoc} 279 * 280 * @see org.jboss.dna.graph.ExecutionContext#getPropertyFactory() 281 */ 282 public PropertyFactory getPropertyFactory() { 283 return context.getPropertyFactory(); 284 } 285 286 /** 287 * {@inheritDoc} 288 * 289 * @see org.jboss.dna.graph.ExecutionContext#getSubject() 290 */ 291 public Subject getSubject() { 292 return context.getSubject(); 293 } 294 }