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.plugins.repository.workspace; 017 018import java.io.IOException; 019import java.io.InputStream; 020import java.util.Map; 021 022import org.apache.avalon.framework.parameters.ParameterException; 023import org.apache.avalon.framework.parameters.Parameters; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.avalon.framework.service.Serviceable; 027import org.apache.cocoon.ProcessingException; 028import org.apache.cocoon.environment.ObjectModelHelper; 029import org.apache.cocoon.environment.Response; 030import org.apache.cocoon.environment.SourceResolver; 031import org.apache.cocoon.reading.AbstractReader; 032import org.apache.cocoon.reading.Reader; 033import org.apache.commons.io.IOUtils; 034import org.apache.commons.lang.StringUtils; 035import org.apache.excalibur.source.SourceUtil; 036import org.xml.sax.SAXException; 037 038import org.ametys.plugins.repository.AmetysObject; 039import org.ametys.plugins.repository.AmetysObjectResolver; 040import org.ametys.plugins.repository.metadata.BinaryMetadata; 041import org.ametys.plugins.repository.metadata.CompositeMetadata; 042import org.ametys.plugins.repository.metadata.File; 043import org.ametys.plugins.repository.metadata.Folder; 044import org.ametys.plugins.repository.metadata.ModifiableMetadataAwareAmetysObject; 045import org.ametys.plugins.repository.metadata.RichText; 046 047/** 048 * {@link Reader} for exposing a binary property from a JCR repository.<br> 049 * Mime type can be forced by using parameter <code>mime-type</code>. 050 */ 051public class BinaryMetadataReader extends AbstractReader implements Serviceable 052{ 053 private AmetysObjectResolver _resolver; 054 private String _mimeType; 055 private String _mdName; 056 private String _compositePath; 057 private String _richtextPath; 058 private String _mdType; 059 private String _aoId; 060 061 public void service(ServiceManager manager) throws ServiceException 062 { 063 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 064 } 065 066 @Override 067 public void setup(SourceResolver res, Map objModel, String src, Parameters params) throws ProcessingException, SAXException, IOException 068 { 069 super.setup(res, objModel, src, params); 070 071 try 072 { 073 _mimeType = params.getParameter("mime-type"); 074 _mdName = params.getParameter("name"); 075 _compositePath = params.getParameter("compositePath"); 076 _richtextPath = params.getParameter("richtextPath"); 077 _mdType = params.getParameter("type"); 078 _aoId = params.getParameter("id"); 079 } 080 catch (ParameterException e) 081 { 082 throw new ProcessingException(e); 083 } 084 } 085 086 @Override 087 public String getMimeType() 088 { 089 if (!StringUtils.isEmpty(_mimeType)) 090 { 091 return _mimeType; 092 } 093 094 return _getMimeType(); 095 } 096 097 @SuppressWarnings({"resource", "deprecation"}) 098 public void generate() throws IOException, SAXException, ProcessingException 099 { 100 try 101 { 102 String filename = null; 103 long length = 0; 104 105 AmetysObject ao = _getAmetysObject(); 106 107 if (getLogger().isInfoEnabled()) 108 { 109 getLogger().info("Trying to read a binary for object of id: '" + _aoId + "'"); 110 } 111 112 CompositeMetadata holder = _getCompositeMetadata (ao); 113 InputStream is = null; 114 115 if (_mdType.equals("RICHTEXT-CONTENT")) 116 { 117 String[] rtTokens = _richtextPath.split("/"); 118 RichText rt = holder.getRichText(rtTokens[0]); 119 120 length = rt.getLength(); 121 filename = rtTokens[0]; 122 is = rt.getInputStream(); 123 } 124 else if (_mdType.equals("RICHTEXT")) 125 { 126 RichText rt = holder.getRichText(_mdName); 127 128 length = rt.getLength(); 129 filename = _mdName; 130 is = rt.getInputStream(); 131 } 132 else if (_mdType.equals("BINARY")) 133 { 134 BinaryMetadata binaryMetadata = holder.getBinaryMetadata(_mdName); 135 filename = binaryMetadata.getFilename(); 136 is = binaryMetadata.getInputStream(); 137 length = binaryMetadata.getLength(); 138 } 139 else if (_mdType.equals("FILE-CONTENT")) 140 { 141 //TODO this case is not tested 142 String[] rtTokens = _richtextPath.split("/"); 143 RichText rt = holder.getRichText(rtTokens[0]); 144 length = rt.getLength(); 145 146 Folder folder = rt.getAdditionalDataFolder(); 147 for (int i = 2; i < rtTokens.length - 1; i++) 148 { 149 folder = folder.getFolder(rtTokens[i]); 150 } 151 152 File file = folder.getFile(rtTokens[rtTokens.length - 1]); 153 filename = file.getName(); 154 is = file.getResource().getInputStream(); 155 } 156 157 158 Response response = ObjectModelHelper.getResponse(objectModel); 159 160 response.setHeader("Content-Length", Long.toString(length)); 161 response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); 162 163 SourceUtil.copy(is, out); 164 } 165 catch (Exception e) 166 { 167 throw new ProcessingException("Unable to download binary property of path " + _mdName, e); 168 } 169 finally 170 { 171 IOUtils.closeQuietly(out); 172 } 173 } 174 175 private CompositeMetadata _getCompositeMetadata (AmetysObject ao) 176 { 177 CompositeMetadata holder = ((ModifiableMetadataAwareAmetysObject) ao).getMetadataHolder(); 178 179 // deep search if inside composite metadata 180 if (!_compositePath.isEmpty()) 181 { 182 String[] tokens = _compositePath.split("/"); 183 for (String token : tokens) 184 { 185 holder = holder.getCompositeMetadata(token); 186 } 187 } 188 189 return holder; 190 } 191 192 private String _getMimeType () 193 { 194 AmetysObject ao = _getAmetysObject(); 195 CompositeMetadata holder = _getCompositeMetadata (ao); 196 197 if (_mdType.equals("RICHTEXT-CONTENT")) 198 { 199 String[] rtTokens = _richtextPath.split("/"); 200 RichText rt = holder.getRichText(rtTokens[0]); 201 return rt.getMimeType(); 202 } 203 else if (_mdType.equals("RICHTEXT")) 204 { 205 return holder.getRichText(_mdName).getMimeType(); 206 } 207 else if (_mdType.equals("BINARY")) 208 { 209 return holder.getBinaryMetadata(_mdName).getMimeType(); 210 } 211 else if (_mdType.equals("FILE-CONTENT")) 212 { 213 String[] rtTokens = _richtextPath.split("/"); 214 RichText rt = holder.getRichText(rtTokens[0]); 215 216 Folder folder = rt.getAdditionalDataFolder(); 217 for (int i = 2; i < rtTokens.length - 1; i++) 218 { 219 folder = folder.getFolder(rtTokens[i]); 220 } 221 222 File file = folder.getFile(rtTokens[rtTokens.length - 1]); 223 return file.getResource().getMimeType(); 224 } 225 226 return "application/unknown"; 227 } 228 229 private AmetysObject _getAmetysObject () 230 { 231 if (_aoId.equals("/")) 232 { 233 return _resolver.resolveByPath("/"); 234 } 235 else 236 { 237 return _resolver.resolveById(_aoId); 238 } 239 } 240}