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