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.repositoryapp.jcr; 017 018import java.io.File; 019import java.io.FileInputStream; 020import java.io.IOException; 021import java.io.InputStream; 022import java.text.DateFormat; 023import java.text.ParseException; 024import java.text.SimpleDateFormat; 025import java.time.ZonedDateTime; 026import java.util.ArrayList; 027import java.util.Arrays; 028import java.util.Calendar; 029import java.util.Collections; 030import java.util.GregorianCalendar; 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; 034 035import javax.jcr.Binary; 036import javax.jcr.Node; 037import javax.jcr.RepositoryException; 038import javax.jcr.Session; 039import javax.jcr.Value; 040import javax.jcr.ValueFactory; 041 042import org.apache.avalon.framework.parameters.Parameters; 043import org.apache.avalon.framework.service.ServiceException; 044import org.apache.avalon.framework.service.ServiceManager; 045import org.apache.cocoon.acting.ServiceableAction; 046import org.apache.cocoon.environment.ObjectModelHelper; 047import org.apache.cocoon.environment.Redirector; 048import org.apache.cocoon.environment.Request; 049import org.apache.cocoon.environment.SourceResolver; 050import org.apache.cocoon.servlet.multipart.PartOnDisk; 051import org.apache.commons.lang3.StringUtils; 052 053import org.ametys.core.cocoon.JSonReader; 054import org.ametys.core.util.DateUtils; 055import org.ametys.plugins.repositoryapp.RepositoryProvider; 056import org.ametys.runtime.i18n.I18nizableText; 057import org.ametys.workspaces.repository.jcr.RepositoryDao; 058 059/** 060 * Set value for a property (if the property does not exist, create the property) 061 */ 062public class SetPropertyAction extends ServiceableAction 063{ 064 065 /** The input date format. */ 066 protected static final DateFormat _DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); 067 068 /** The repository provider. */ 069 protected RepositoryProvider _repositoryProvider; 070 071 @Override 072 public void service(ServiceManager serviceManager) throws ServiceException 073 { 074 super.service(serviceManager); 075 _repositoryProvider = (RepositoryProvider) serviceManager.lookup(RepositoryProvider.ROLE); 076 } 077 078 public Map act(Redirector redirector, SourceResolver sourceResolver, Map objectModel, String source, Parameters parameters) throws Exception 079 { 080 Map<String, Object> result = new HashMap<>(); 081 082 Request request = ObjectModelHelper.getRequest(objectModel); 083 084 String workspaceName = request.getParameter("workspace"); 085 086 Session session = _repositoryProvider.getSession(workspaceName); 087 088 String nodePath = request.getParameter("path"); 089 String propertyName = request.getParameter("name"); 090 String[] values = request.getParameterValues("value"); 091 String type = request.getParameter("type"); 092 boolean multiple = Boolean.valueOf(request.getParameter("multiple")); 093 094 if (getLogger().isDebugEnabled()) 095 { 096 getLogger().debug("Trying to add property: '" + propertyName + "' to the node at path: '" + nodePath + "'"); 097 } 098 099 String relPath = RepositoryDao.removeLeadingSlash(nodePath); 100 101 // Get the parent node 102 Node node = null; 103 if (StringUtils.isEmpty(relPath)) 104 { 105 node = session.getRootNode(); 106 } 107 else 108 { 109 node = session.getRootNode().getNode(relPath); 110 } 111 112 // Get the type in jcr format (e.g. javax.jcr.PropertyType.BOOLEAN) 113 int jcrType = javax.jcr.PropertyType.valueFromName(StringUtils.capitalize(type)); 114 115 try 116 { 117 // Add or update property to the node 118 if (type.equalsIgnoreCase("Date")) 119 { 120 _setDate(node, propertyName, values); 121 } 122 else if (type.equalsIgnoreCase("Binary")) 123 { 124 _setBinary(session, request, node, propertyName); 125 } 126 else if (type.equalsIgnoreCase("Reference")) 127 { 128 _setReference(session, node, propertyName, values, multiple); 129 } 130 else 131 { 132 _setValue(node, propertyName, values, multiple, jcrType); 133 } 134 135 result.put("success", true); 136 } 137 catch (RepositoryException e) 138 { 139 getLogger().error("Unable to set value " + Arrays.toString(values) + " for property '" + propertyName + "'", e); 140 result.put("success", false); 141 result.put("message", e.toString()); 142 } 143 catch (ParseException e) 144 { 145 getLogger().error("Unable to set value " + Arrays.toString(values) + " for property '" + propertyName + "'", e); 146 result.put("success", false); 147 I18nizableText message = new I18nizableText("plugin.repositoryapp", "PLUGINS_REPOSITORYAPP_CREATE_PROP_ERROR_DATE", Collections.singletonMap("error", new I18nizableText(e.getMessage()))); 148 result.put("message", message); 149 } 150 catch (Exception e) 151 { 152 getLogger().error("Unable to set value " + Arrays.toString(values) + " for property '" + propertyName + "'", e); 153 result.put("success", false); 154 result.put("message", e.toString()); 155 } 156 157 request.setAttribute(JSonReader.OBJECT_TO_READ, result); 158 return EMPTY_MAP; 159 } 160 161 private void _setDate(Node node, String propertyName, String[] value) throws RepositoryException, ParseException 162 { 163 //create calendar date from string value 164 ZonedDateTime zdt = DateUtils.parseZonedDateTime(value[0]); 165 Calendar cal = GregorianCalendar.from(zdt); 166 167 node.setProperty(propertyName, cal); 168 } 169 170 private void _setBinary(Session session, Request request, Node node, String propertyName) throws RepositoryException, IOException 171 { 172 // The upload was either sent as the property name (when modified) or as "fieldValue" (when added). 173 PartOnDisk uploadedFilePart = (PartOnDisk) request.get(propertyName); 174 if (uploadedFilePart == null) 175 { 176 uploadedFilePart = (PartOnDisk) request.get("fieldValue"); 177 } 178 179 File uploadedFile = (uploadedFilePart != null) ? uploadedFilePart.getFile() : null; 180 InputStream is = new FileInputStream(uploadedFile); 181 182 Binary binary = session.getValueFactory().createBinary(is); 183 node.setProperty(propertyName, binary); 184 } 185 186 private void _setReference(Session session, Node node, String propertyName, String[] value, boolean multiple) throws RepositoryException 187 { 188 List<Value> values = new ArrayList<>(); 189 ValueFactory vf = session.getValueFactory(); 190 for (String v : value) 191 { 192 values.add(vf.createValue(session.getNodeByIdentifier(v))); 193 } 194 195 boolean isMultiple = multiple || node.hasProperty(propertyName) && node.getProperty(propertyName).getDefinition().isMultiple(); 196 if (isMultiple) 197 { 198 node.setProperty(propertyName, values.toArray(new Value[values.size()])); 199 } 200 else 201 { 202 node.setProperty(propertyName, values.get(0)); 203 } 204 } 205 206 private void _setValue(Node node, String propertyName, String[] value, boolean multiple, int jcrType) throws RepositoryException 207 { 208 boolean isMultiple = multiple || node.hasProperty(propertyName) && node.getProperty(propertyName).getDefinition().isMultiple(); 209 if (isMultiple) 210 { 211 node.setProperty(propertyName, value, jcrType); 212 } 213 else 214 { 215 node.setProperty(propertyName, value[0], jcrType); 216 } 217 } 218 219}