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 }