001/* 002 * Copyright 2010 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.cms.content; 017 018import java.io.IOException; 019import java.io.InputStream; 020import java.io.Serializable; 021import java.net.URLDecoder; 022import java.util.Arrays; 023import java.util.Collection; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Map; 027 028import org.apache.avalon.framework.parameters.ParameterException; 029import org.apache.avalon.framework.parameters.Parameters; 030import org.apache.avalon.framework.service.ServiceException; 031import org.apache.avalon.framework.service.ServiceManager; 032import org.apache.avalon.framework.service.Serviceable; 033import org.apache.cocoon.ProcessingException; 034import org.apache.cocoon.caching.CacheableProcessingComponent; 035import org.apache.cocoon.environment.ObjectModelHelper; 036import org.apache.cocoon.environment.Request; 037import org.apache.cocoon.environment.Response; 038import org.apache.cocoon.environment.SourceResolver; 039import org.apache.cocoon.reading.ServiceableReader; 040import org.apache.commons.io.IOUtils; 041import org.apache.commons.lang.StringUtils; 042import org.apache.excalibur.source.SourceValidity; 043import org.xml.sax.SAXException; 044 045import org.ametys.cms.repository.Content; 046import org.ametys.core.util.ImageHelper; 047import org.ametys.core.util.cocoon.AbstractResourceReader; 048import org.ametys.core.util.cocoon.InvalidSourceValidity; 049import org.ametys.plugins.repository.AmetysObjectResolver; 050import org.ametys.plugins.repository.metadata.BinaryMetadata; 051import org.ametys.plugins.repository.metadata.CompositeMetadata; 052import org.ametys.plugins.repository.metadata.CompositeMetadata.MetadataType; 053import org.ametys.plugins.repository.metadata.MetadataAwareAmetysObject; 054import org.ametys.plugins.repository.version.VersionableAmetysObject; 055 056/** 057 * Reader for binary or file metadata. 058 */ 059public class FileReader extends AbstractResourceReader implements Serviceable, CacheableProcessingComponent 060{ 061 /** The ametys object resolver. */ 062 protected AmetysObjectResolver _resolver; 063 064 private MetadataAwareAmetysObject _ametysObject; 065 private BinaryMetadata _binary; 066 067 private String _path; 068 069 @Override 070 public void service(ServiceManager serviceManager) throws ServiceException 071 { 072 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 073 } 074 075 @Override 076 public void doSetup(SourceResolver res, Map objModel, String src, Parameters par) throws ProcessingException, IOException 077 { 078 _ametysObject = getAmetysObject(); 079 080 CompositeMetadata metadata = _ametysObject.getMetadataHolder(); 081 082 try 083 { 084 _path = parameters.getParameter("path"); 085 } 086 catch (ParameterException e) 087 { 088 throw new ProcessingException("The path parameter is mandatory for reading binary metadata.", e); 089 } 090 091 List<String> pathElements = Arrays.asList(_path.split("/")); 092 093 Iterator<String> it = pathElements.iterator(); 094 095 while (it.hasNext()) 096 { 097 String pathElement = it.next(); 098 099 if (it.hasNext()) 100 { 101 // not the last segment : it is a composite 102 metadata = metadata.getCompositeMetadata(URLDecoder.decode(pathElement, "UTF-8")); 103 } 104 else 105 { 106 String metadataName = URLDecoder.decode(pathElement, "UTF-8"); 107 if (metadata.getType(metadataName) != MetadataType.BINARY) 108 { 109 throw new UnsupportedOperationException("Only binary metadata are allowed"); 110 } 111 112 _binary = metadata.getBinaryMetadata(metadataName); 113 } 114 } 115 } 116 117 /** 118 * Get the ametys object. 119 * @return the ametys object. 120 * @throws ProcessingException if the information provided was insufficient to resolve an object. 121 */ 122 protected MetadataAwareAmetysObject getAmetysObject() throws ProcessingException 123 { 124 MetadataAwareAmetysObject object = null; 125 126 Request request = ObjectModelHelper.getRequest(objectModel); 127 String objectPath = parameters.getParameter("objectPath", request.getParameter("objectPath")); 128 String objectId = parameters.getParameter("objectId", request.getParameter("objectId")); 129 // Legacy parameter name. 130 if (StringUtils.isBlank(objectId)) 131 { 132 objectId = parameters.getParameter("contentId", request.getParameter("contentId")); 133 } 134 135 if (StringUtils.isNotBlank(objectId)) 136 { 137 object = _resolver.resolveById(objectId); 138 } 139 else if (StringUtils.isNotBlank(objectPath)) 140 { 141 objectPath = objectPath.replaceAll("%3A", ":"); 142 object = _resolver.resolveByPath(objectPath); 143 } 144 else 145 { 146 object = (Content) request.getAttribute(Content.class.getName()); 147 } 148 149 if (object == null) 150 { 151 throw new ProcessingException("The object ID parameter is mandatory for reading binary metadata."); 152 } 153 154 String revision = parameters.getParameter("contentVersion", null); 155 if (StringUtils.isNotEmpty(revision) && object instanceof VersionableAmetysObject) 156 { 157 ((VersionableAmetysObject) object).switchToRevision(revision); 158 } 159 160 return object; 161 } 162 163 @Override 164 protected InputStream getInputStream() 165 { 166 return _binary.getInputStream(); 167 } 168 169 @Override 170 protected String getFilename() 171 { 172 return _binary.getFilename(); 173 } 174 175 @Override 176 protected String getEncodedFilename() 177 { 178 return null; 179 } 180 181 @Override 182 protected long getLength() 183 { 184 return _binary.getLength(); 185 } 186 187 @Override 188 public Serializable getKey() 189 { 190 return _path + getKeySuffix(); 191 } 192 193 @Override 194 public SourceValidity getValidity() 195 { 196 return new InvalidSourceValidity(); 197 } 198 199 @Override 200 public long getLastModified() 201 { 202 if (_binary != null) 203 { 204 return _binary.getLastModified().getTime(); 205 } 206 207 return super.getLastModified(); 208 } 209 210 @Override 211 public String getMimeType() 212 { 213 if (_binary != null) 214 { 215 return _binary.getMimeType(); 216 } 217 218 return super.getMimeType(); 219 } 220 221 @Override 222 public void recycle() 223 { 224 super.recycle(); 225 226 _binary = null; 227 _ametysObject = null; 228 } 229}