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 }