001/* 002 * Copyright 2022 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.script; 017 018import java.lang.reflect.Array; 019import java.util.List; 020 021import javax.jcr.Node; 022import javax.jcr.Property; 023import javax.jcr.PropertyType; 024import javax.jcr.RepositoryException; 025import javax.jcr.Value; 026 027import org.apache.commons.lang3.ArrayUtils; 028import org.apache.commons.lang3.StringUtils; 029 030import org.ametys.plugins.repository.data.holder.DataHolder; 031import org.ametys.plugins.repository.data.holder.ModifiableDataHolder; 032import org.ametys.runtime.model.exception.BadItemTypeException; 033import org.ametys.runtime.model.type.ElementType; 034import org.ametys.runtime.model.type.ModelItemType; 035 036/** 037 * Helper methods to manipulate some objects in the script tool. Arrays and lists are not managed the same way depending of JS engine used in the JVM. 038 */ 039public final class RepositoryScriptHelper 040{ 041 private RepositoryScriptHelper() 042 { 043 // Utility class 044 } 045 046 /** 047 * Helper to set ambiguous object values from a node property 048 * @param node the node 049 * @param name the property name 050 * @param values the property values as String[] or Value[] 051 * @throws RepositoryException if an error occurred 052 */ 053 public static void setProperty(Node node, String name, Object values) throws RepositoryException 054 { 055 Object javaValues = values; 056 if (values instanceof List) 057 { 058 List<?> list = (List<?>) values; 059 if (list.isEmpty()) 060 { 061 javaValues = new Value[0]; 062 } 063 else if (list.get(0) instanceof String) 064 { 065 javaValues = list.toArray(new String[list.size()]); 066 } 067 else if (list.get(0) instanceof Value) 068 { 069 javaValues = list.toArray(new Value[list.size()]); 070 } 071 } 072 _setProperty(node, name, javaValues); 073 } 074 075 private static void _setProperty(Node node, String name, Object values) throws RepositoryException 076 { 077 if (values instanceof String[]) 078 { 079 node.setProperty(name, (String[]) values); 080 } 081 else if (values instanceof Value[]) 082 { 083 node.setProperty(name, (Value[]) values); 084 } 085 else if (values instanceof String) 086 { 087 node.setProperty(name, (String) values); 088 } 089 else if (values instanceof Boolean) 090 { 091 node.setProperty(name, (Boolean) values); 092 } 093 else if (values instanceof Long) 094 { 095 node.setProperty(name, (Long) values); 096 } 097 else if (values instanceof Integer) 098 { 099 node.setProperty(name, ((Integer) values).longValue()); 100 } 101 else if (values instanceof Double) 102 { 103 node.setProperty(name, (Double) values); 104 } 105 else if (values instanceof Float) 106 { 107 node.setProperty(name, ((Float) values).doubleValue()); 108 } 109 else 110 { 111 Class< ? > clazz = values.getClass(); 112 throw new IllegalArgumentException("argument values (" + values + ") is of unsupported type by RepositoryScriptHelper#setProperty: '" + clazz + "'"); 113 } 114 } 115 116 /** 117 * Helper to convert a single-valued property to a multi-valued property. 118 * This helper checks that property exists and that it is not already multiple. 119 * @param node the node holding the property 120 * @param propertyName the property's name 121 * @return true if changes was made 122 * @throws RepositoryException if an error occurred 123 */ 124 public static boolean convertSingleToMultipleProperty (Node node, String propertyName) throws RepositoryException 125 { 126 boolean needSave = false; 127 if (node.hasProperty(propertyName)) 128 { 129 Property property = node.getProperty(propertyName); 130 if (!property.getDefinition().isMultiple()) 131 { 132 Value value = property.getValue(); 133 if (value.getType() == PropertyType.STRING) 134 { 135 String valueAsStr = value.getString(); 136 property.remove(); 137 138 if (!StringUtils.isEmpty(valueAsStr)) 139 { 140 String[] strArray = value.getString().split(","); 141 node.setProperty(propertyName, strArray); 142 } 143 else 144 { 145 node.setProperty(propertyName, new String[0]); 146 } 147 } 148 else 149 { 150 Value[] values = ArrayUtils.toArray(value); 151 node.setProperty(propertyName, values); 152 } 153 154 needSave = true; 155 } 156 } 157 158 return needSave; 159 } 160 161 /** 162 * Set the value of a {@link ModifiableDataHolder}. 163 * If a multiple value is provided as a {@link List} instead of an array, this method will try to convert it into 164 * an array based on the available {@link ElementType} of the {@link DataHolder}. 165 * 166 * @param dataHolder the data holder to update 167 * @param name the data name to update 168 * @param value the value 169 * @param type the type of the data 170 */ 171 @SuppressWarnings("unchecked") 172 public static void setValueOfType(ModifiableDataHolder dataHolder, String name, Object value, String type) 173 { 174 if (value instanceof List list) 175 { 176 ModelItemType modelItemType = dataHolder.getModelItemTypeExtensionPoint().getExtension(type); 177 if (modelItemType == null) 178 { 179 throw new BadItemTypeException("Type '" + type + "'does not exist for the given DataHolder (" + dataHolder.getRepositoryData().toString() + "). Impossible to use setValue with it."); 180 } 181 else if (modelItemType instanceof ElementType elementType) 182 { 183 Class managedClass = elementType.getManagedClass(); 184 Object[] array = (Object[]) Array.newInstance(managedClass, list.size()); 185 dataHolder.setValue(name, list.toArray(array), type); 186 } 187 else 188 { 189 throw new BadItemTypeException("Type '" + type + "'is not associated with an ElementType. Impossible to use setValue with it."); 190 } 191 } 192 else 193 { 194 dataHolder.setValue(name, value, type); 195 } 196 } 197 198 /** 199 * Set the value of a {@link ModifiableDataHolder}. 200 * If a multiple value is provided as a {@link List} instead of an array, this method will try to convert it into 201 * an array based on the managed class of the type of data at path name. 202 * 203 * @param dataHolder the data holder to update 204 * @param name the data name to update 205 * @param value the value 206 */ 207 @SuppressWarnings("unchecked") 208 public static void setValue(ModifiableDataHolder dataHolder, String name, Object value) 209 { 210 if (value instanceof List list) 211 { 212 ModelItemType itemType = dataHolder.getType(name); 213 if (itemType instanceof ElementType elementType) 214 { 215 Class managedClass = elementType.getManagedClass(); 216 Object[] array = (Object[]) Array.newInstance(managedClass, list.size()); 217 dataHolder.setValue(name, list.toArray(array)); 218 } 219 else 220 { 221 throw new BadItemTypeException("Item at path '" + name + "' is not associated with an ElementType. Impossible to use setValue with it."); 222 } 223 } 224 else 225 { 226 dataHolder.setValue(name, value); 227 } 228 } 229 230}