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.File; 019import java.io.FileInputStream; 020import java.io.InputStream; 021import java.text.ParseException; 022import java.text.SimpleDateFormat; 023import java.util.Arrays; 024import java.util.Collections; 025import java.util.Date; 026import java.util.HashMap; 027import java.util.Map; 028 029import org.apache.avalon.framework.parameters.ParameterException; 030import org.apache.avalon.framework.parameters.Parameters; 031import org.apache.avalon.framework.service.ServiceException; 032import org.apache.avalon.framework.service.ServiceManager; 033import org.apache.cocoon.ProcessingException; 034import org.apache.cocoon.acting.ServiceableAction; 035import org.apache.cocoon.environment.ObjectModelHelper; 036import org.apache.cocoon.environment.Redirector; 037import org.apache.cocoon.environment.Request; 038import org.apache.cocoon.environment.SourceResolver; 039import org.apache.cocoon.servlet.multipart.PartOnDisk; 040import org.apache.commons.lang3.exception.ExceptionUtils; 041 042import org.ametys.core.cocoon.JSonReader; 043import org.ametys.core.util.LambdaUtils; 044import org.ametys.plugins.repository.AmetysObject; 045import org.ametys.plugins.repository.AmetysObjectResolver; 046import org.ametys.plugins.repository.metadata.CompositeMetadata.MetadataType; 047import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata; 048import org.ametys.plugins.repository.metadata.ModifiableFile; 049import org.ametys.plugins.repository.metadata.ModifiableFolder; 050import org.ametys.plugins.repository.metadata.ModifiableMetadataAwareAmetysObject; 051import org.ametys.plugins.repository.metadata.ModifiableRichText; 052import org.ametys.runtime.i18n.I18nizableTextParameter; 053import org.ametys.runtime.i18n.I18nizableText; 054 055/** 056 * Set value for a metadata 057 */ 058public class SetMetadataAction extends ServiceableAction 059{ 060 static SimpleDateFormat _DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); 061 private AmetysObjectResolver _resolver; 062 063 @Override 064 public void service(ServiceManager serviceManager) throws ServiceException 065 { 066 super.service(serviceManager); 067 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 068 } 069 070 public Map act(Redirector redirector, SourceResolver sourceResolver, Map objectModel, String source, Parameters parameters) throws Exception 071 { 072 Request request = ObjectModelHelper.getRequest(objectModel); 073 074 String id = null; 075 String name = null; 076 String compositePath = null; 077 String richtextPath = null; 078 boolean multiple; 079 080 String type = null; 081 String fileFieldId = null; 082 083 try 084 { 085 id = parameters.getParameter("id"); 086 name = parameters.getParameter("name"); 087 compositePath = parameters.getParameter("cPath"); 088 richtextPath = parameters.getParameter("rtPath"); 089 type = parameters.getParameter("type"); 090 fileFieldId = parameters.getParameter("filefieldid"); 091 multiple = parameters.getParameterAsBoolean("multiple", false); 092 } 093 catch (ParameterException e) 094 { 095 throw new ProcessingException("Missing at least one parameter", e); 096 } 097 098 if (getLogger().isInfoEnabled()) 099 { 100 getLogger().info("Setting metadata '" + name + "' of the AmetysObject of id '" + id + "'"); 101 } 102 103 AmetysObject ao = null; 104 105 if (id.equals("/")) 106 { 107 ao = _resolver.resolveByPath("/"); 108 } 109 else 110 { 111 ao = _resolver.resolveById(id); 112 } 113 114 String[] values = request.getParameterValues("value"); 115 116 Map<String, Object> result = new HashMap<>(); 117 118 try 119 { 120 ModifiableCompositeMetadata holder = _getHolderInComposite((ModifiableMetadataAwareAmetysObject) ao, compositePath); 121 122 //changing value of a metadata in a composite 123 if (richtextPath.isEmpty()) 124 { 125 _setMetadataOutsideRT(holder, type, name, values, multiple); 126 } 127 //changing a value inside a richtext 128 else if (richtextPath.split("/").length == 1) 129 { 130 _setMetadataInsideRT(request, holder, name, values[0], fileFieldId, richtextPath); 131 } 132 else //TODO this part is not tested !! 133 { 134 _setMetadataInsideRTDataFolder(request, holder, name, values[0], fileFieldId, richtextPath); 135 } 136 137 ((ModifiableMetadataAwareAmetysObject) ao).saveChanges(); 138 139 result.put("success", true); 140 } 141 catch (Exception e) 142 { 143 getLogger().error("Unable to set value " + values[0] + " for metadata '" + name + "'", e); 144 result.put("success", false); 145 146 Throwable rootCause = ExceptionUtils.getRootCause(e); 147 148 if (rootCause instanceof ParseException) 149 { 150 Map<String, I18nizableTextParameter> params = Collections.singletonMap("error", new I18nizableText(e.getMessage())); 151 result.put("message", new I18nizableText("plugin.repositoryapp", "PLUGINS_REPOSITORYAPP_CREATE_PROP_ERROR_DATE", params)); 152 } 153 else 154 { 155 result.put("message", e.toString()); 156 } 157 } 158 159 request.setAttribute(JSonReader.OBJECT_TO_READ, result); 160 return EMPTY_MAP; 161 } 162 163 private ModifiableCompositeMetadata _getHolderInComposite(ModifiableMetadataAwareAmetysObject ao, String compositePath) 164 { 165 ModifiableCompositeMetadata holder = ao.getMetadataHolder(); 166 167 // deep search in composite metadata 168 if (!compositePath.isEmpty()) 169 { 170 String[] tokens = compositePath.split("/"); 171 for (int i = 0; i < tokens.length; i++) 172 { 173 holder = holder.getCompositeMetadata(tokens[i]); 174 } 175 } 176 177 return holder; 178 } 179 180 private void _setMetadataOutsideRT(ModifiableCompositeMetadata holder, String type, String name, String[] values, boolean multiple) throws Exception 181 { 182 //switch according to type 183 //convert value to correct type if not string and set new value 184 MetadataType mdType = MetadataType.valueOf(type.toUpperCase()); 185 switch (mdType) 186 { 187 case DATE: 188 if (multiple) 189 { 190 Date[] dateValues = Arrays.stream(values).map(LambdaUtils.wrap(_DATE_FORMAT::parse)).toArray(Date[]::new); 191 holder.setMetadata(name, dateValues); 192 } 193 else 194 { 195 Date dateVal = _DATE_FORMAT.parse(values[0]); 196 holder.setMetadata(name, dateVal); 197 } 198 break; 199 case STRING: 200 if (multiple) 201 { 202 holder.setMetadata(name, values); 203 } 204 else 205 { 206 holder.setMetadata(name, values[0]); 207 } 208 break; 209 case LONG: 210 if (multiple) 211 { 212 long[] longValues = Arrays.stream(values).mapToLong(Long::parseLong).toArray(); 213 holder.setMetadata(name, longValues); 214 } 215 else 216 { 217 Long longVal = Long.parseLong(values[0]); 218 holder.setMetadata(name, longVal); 219 } 220 break; 221 case DOUBLE: 222 if (multiple) 223 { 224 double[] doubleValues = Arrays.stream(values).mapToDouble(Double::parseDouble).toArray(); 225 holder.setMetadata(name, doubleValues); 226 } 227 else 228 { 229 Double doubleVal = Double.parseDouble(values[0]); 230 holder.setMetadata(name, doubleVal); 231 } 232 233 break; 234 case BOOLEAN: 235 Boolean booleanVal = Boolean.parseBoolean(values[0]); 236 holder.setMetadata(name, booleanVal); 237 break; 238 case COMPOSITE: 239 240 break; 241 case BINARY: 242 243 break; 244 case RICHTEXT: 245 246 break; 247 case OBJECT_COLLECTION: 248 // TODO? 249 break; 250 default: 251 break; 252 } 253 } 254 255 private void _setMetadataInsideRT(Request request, ModifiableCompositeMetadata holder, String name, String value, String fileFieldId, String richtextPath) throws Exception 256 { 257 String[] rtTokens = richtextPath.split("/"); 258 ModifiableRichText rt = holder.getRichText(rtTokens[0]); 259 260 // update correct property 261 if (name.equals("mime-type")) 262 { 263 rt.setMimeType(value); 264 } 265 else if (name.equals("last-modified-date")) 266 { 267 Date dateVal = _DATE_FORMAT.parse(value); 268 rt.setLastModified(dateVal); 269 } 270 else if (name.equals("encoding")) 271 { 272 rt.setEncoding(value); 273 } 274 else if (name.equals("data")) 275 { 276 PartOnDisk uploadedFilePart = (PartOnDisk) request.get(fileFieldId); 277 File uploadedFile = (uploadedFilePart != null) ? uploadedFilePart.getFile() : null; 278 279 if (uploadedFile != null) 280 { 281 InputStream is = new FileInputStream(uploadedFile); 282 rt.setInputStream(is); 283 } 284 } 285 else if (name.equals("length")) 286 { 287 //not possible to change length 288 } 289 } 290 291 private void _setMetadataInsideRTDataFolder(Request request, ModifiableCompositeMetadata holder, String name, String value, String fileFieldId, String richtextPath) throws Exception 292 { 293 String[] rtTokens = richtextPath.split("/"); 294 ModifiableRichText rt = holder.getRichText(rtTokens[0]); 295 ModifiableFolder folder = rt.getAdditionalDataFolder(); 296 297 for (int i = 2; i < rtTokens.length - 1; i++) 298 { 299 folder = folder.getFolder(rtTokens[i]); 300 } 301 302 ModifiableFile file = folder.getFile(rtTokens[rtTokens.length - 1]); 303 304 // update correct property 305 if (name.equals("mime-type")) 306 { 307 file.getResource().setMimeType(value); 308 } 309 else if (name.equals("last-modified-date")) 310 { 311 Date dateVal = _DATE_FORMAT.parse(value); 312 file.getResource().setLastModified(dateVal); 313 } 314 else if (name.equals("encoding")) 315 { 316 file.getResource().setEncoding(value); 317 } 318 else if (name.equals("data")) 319 { 320 PartOnDisk uploadedFilePart = (PartOnDisk) request.get(fileFieldId); 321 File uploadedFile = (uploadedFilePart != null) ? uploadedFilePart.getFile() : null; 322 InputStream is = new FileInputStream(uploadedFile); 323 file.getResource().setInputStream(is); 324 } 325 else if (name.equals("length")) 326 { 327 //not possible to change length 328 } 329 } 330}