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.util.Collections;
027 import java.util.HashSet;
028 import java.util.Set;
029 import javax.jcr.Node;
030 import javax.jcr.PropertyIterator;
031 import javax.jcr.PropertyType;
032 import javax.jcr.RepositoryException;
033 import javax.jcr.Value;
034 import net.jcip.annotations.Immutable;
035 import org.jboss.dna.common.util.CheckArg;
036 import org.jboss.dna.common.util.Logger;
037 import org.jboss.dna.graph.properties.Name;
038 import org.jboss.dna.graph.properties.NamespaceRegistry;
039 import org.jboss.dna.graph.properties.Path;
040 import org.jboss.dna.graph.properties.Property;
041 import org.jboss.dna.graph.properties.ValueFactories;
042 import org.jboss.dna.graph.sequencers.SequencerContext;
043 import org.jboss.dna.graph.sequencers.StreamSequencer;
044 import org.jboss.dna.repository.RepositoryI18n;
045 import org.jboss.dna.repository.mimetype.MimeType;
046 import org.jboss.dna.repository.util.JcrExecutionContext;
047
048 /**
049 * Contains context information that is passed to {@link StreamSequencer stream sequencers}, including information about the input
050 * node containing the data being sequenced.
051 *
052 * @author John Verhaeg
053 */
054 @Immutable
055 public class SequencerNodeContext implements SequencerContext {
056
057 private final javax.jcr.Property sequencedProperty;
058 private final ValueFactories factories;
059 private final Path path;
060 private final Set<Property> props;
061 private final JcrExecutionContext context;
062
063 SequencerNodeContext( Node input,
064 javax.jcr.Property sequencedProperty,
065 JcrExecutionContext context ) throws RepositoryException {
066 assert input != null;
067 assert sequencedProperty != null;
068 assert context != null;
069 this.context = context;
070 this.sequencedProperty = sequencedProperty;
071 this.factories = context.getValueFactories();
072 // Translate JCR path and property values to DNA constructs and cache them to improve performance and prevent
073 // RepositoryException from being thrown by getters
074 // Note: getMimeType() will still operate lazily, and thus throw a SequencerException, since it is very intrusive and
075 // potentially slow-running.
076 path = factories.getPathFactory().create(input.getPath());
077 Set<Property> props = new HashSet<Property>();
078 for (PropertyIterator iter = input.getProperties(); iter.hasNext();) {
079 javax.jcr.Property jcrProp = iter.nextProperty();
080 Property prop;
081 if (jcrProp.getDefinition().isMultiple()) {
082 Value[] jcrVals = jcrProp.getValues();
083 Object[] vals = new Object[jcrVals.length];
084 int ndx = 0;
085 for (Value jcrVal : jcrVals) {
086 vals[ndx++] = convert(factories, jcrProp.getName(), jcrVal);
087 }
088 prop = context.getPropertyFactory().create(factories.getNameFactory().create(jcrProp.getName()), vals);
089 } else {
090 Value jcrVal = jcrProp.getValue();
091 Object val = convert(factories, jcrProp.getName(), jcrVal);
092 prop = context.getPropertyFactory().create(factories.getNameFactory().create(jcrProp.getName()), val);
093 }
094 props.add(prop);
095 }
096 this.props = Collections.unmodifiableSet(props);
097 }
098
099 private Object convert( ValueFactories factories,
100 String name,
101 Value jcrValue ) throws RepositoryException {
102 switch (jcrValue.getType()) {
103 case PropertyType.BINARY: {
104 return factories.getBinaryFactory().create(jcrValue.getStream());
105 }
106 case PropertyType.BOOLEAN: {
107 return factories.getBooleanFactory().create(jcrValue.getBoolean());
108 }
109 case PropertyType.DATE: {
110 return factories.getDateFactory().create(jcrValue.getDate());
111 }
112 case PropertyType.DOUBLE: {
113 return factories.getDoubleFactory().create(jcrValue.getDouble());
114 }
115 case PropertyType.LONG: {
116 return factories.getLongFactory().create(jcrValue.getLong());
117 }
118 case PropertyType.NAME: {
119 return factories.getNameFactory().create(jcrValue.getString());
120 }
121 case PropertyType.PATH: {
122 return factories.getPathFactory().create(jcrValue.getString());
123 }
124 case PropertyType.REFERENCE: {
125 return factories.getReferenceFactory().create(jcrValue.getString());
126 }
127 case PropertyType.STRING: {
128 return factories.getStringFactory().create(jcrValue.getString());
129 }
130 default: {
131 throw new RepositoryException(RepositoryI18n.unknownPropertyValueType.text(name, jcrValue.getType()));
132 }
133 }
134 }
135
136 /**
137 * {@inheritDoc}
138 */
139 public ValueFactories getFactories() {
140 return factories;
141 }
142
143 /**
144 * {@inheritDoc}
145 *
146 * @see org.jboss.dna.graph.sequencers.SequencerContext#getInputPath()
147 */
148 public Path getInputPath() {
149 return path;
150 }
151
152 /**
153 * {@inheritDoc}
154 *
155 * @see org.jboss.dna.graph.sequencers.SequencerContext#getInputProperties()
156 */
157 public Set<Property> getInputProperties() {
158 return props;
159 }
160
161 /**
162 * {@inheritDoc}
163 *
164 * @see org.jboss.dna.graph.sequencers.SequencerContext#getInputProperty(org.jboss.dna.graph.properties.Name)
165 */
166 public Property getInputProperty( Name name ) {
167 CheckArg.isNotNull(name, "name");
168 for (Property prop : props) {
169 if (name.equals(prop.getName())) {
170 return prop;
171 }
172 }
173 return null;
174 }
175
176 /**
177 * {@inheritDoc}
178 *
179 * @see org.jboss.dna.graph.sequencers.SequencerContext#getMimeType()
180 */
181 @SuppressWarnings( "null" )
182 // The need for the SuppressWarnings looks like an Eclipse bug
183 public String getMimeType() {
184 SequencerException err = null;
185 String mimeType = null;
186 InputStream stream = null;
187 try {
188 stream = sequencedProperty.getStream();
189 mimeType = MimeType.of(path.getLastSegment().getName().getLocalName(), stream);
190 return mimeType;
191 } catch (Exception error) {
192 err = new SequencerException(error);
193 } finally {
194 if (stream != null) {
195 try {
196 stream.close();
197 } catch (IOException error) {
198 // Only throw exception if an exception was not already thrown
199 if (err == null) err = new SequencerException(error);
200 }
201 }
202 }
203 if (err != null) throw err;
204 return mimeType;
205 }
206
207 /**
208 * {@inheritDoc}
209 */
210 public NamespaceRegistry getNamespaceRegistry() {
211 return factories.getNameFactory().getNamespaceRegistry();
212 }
213
214 /**
215 * {@inheritDoc}
216 *
217 * @see org.jboss.dna.graph.sequencers.SequencerContext#getLogger(java.lang.Class)
218 */
219 public Logger getLogger( Class<?> clazz ) {
220 return context.getLogger(clazz);
221 }
222
223 /**
224 * {@inheritDoc}
225 *
226 * @see org.jboss.dna.graph.sequencers.SequencerContext#getLogger(java.lang.String)
227 */
228 public Logger getLogger( String name ) {
229 return context.getLogger(name);
230 }
231 }