001/* 002 * Copyright 2019 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.cms.data.type; 017 018import java.util.ArrayList; 019import java.util.Arrays; 020import java.util.List; 021import java.util.Locale; 022import java.util.stream.Collectors; 023 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.configuration.Configurable; 026import org.apache.avalon.framework.configuration.Configuration; 027import org.apache.avalon.framework.configuration.ConfigurationException; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.avalon.framework.service.Serviceable; 031import org.apache.commons.lang3.StringUtils; 032import org.xml.sax.ContentHandler; 033import org.xml.sax.SAXException; 034 035import org.ametys.cms.data.Binary; 036import org.ametys.cms.data.ContentValue; 037import org.ametys.cms.data.ExplorerFile; 038import org.ametys.cms.data.File; 039import org.ametys.core.model.type.AbstractElementType; 040import org.ametys.plugins.repository.AmetysObjectResolver; 041import org.ametys.runtime.model.exception.BadItemTypeException; 042 043/** 044 * Abstract class for file type of elements 045 */ 046public abstract class AbstractFileElementType extends AbstractElementType<File> implements Component, Serviceable, Configurable 047{ 048 /** Type of he file from explorer */ 049 protected static final String __EXPLORER_FILE_TYPE = "explorer"; 050 051 /** Ametys object resolver */ 052 protected AmetysObjectResolver _resolver; 053 054 /** Type of the binary */ 055 protected String _binaryType; 056 057 public void service(ServiceManager manager) throws ServiceException 058 { 059 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 060 } 061 062 public void configure(Configuration configuration) throws ConfigurationException 063 { 064 Configuration typeNode = configuration.getChild("binary-type", false); 065 if (typeNode != null) 066 { 067 _binaryType = typeNode.getValue(null); 068 } 069 070 if (StringUtils.isBlank(_binaryType)) 071 { 072 throw new ConfigurationException("The configuration of binary type should contain a node 'binary-type' with the type of the binary ('metadata', 'explorer', ...)", configuration); 073 } 074 } 075 076 public File castValue(String value) throws BadItemTypeException 077 { 078 return new ExplorerFile(_resolver, value); 079 } 080 081 @Override 082 public String toString(File value) 083 { 084 if (value instanceof ExplorerFile) 085 { 086 return ((ExplorerFile) value).getResourceId(); 087 } 088 else 089 { 090 throw new UnsupportedOperationException("Unable to convert a binary to a string value"); 091 } 092 } 093 094 @Override 095 public void valueToSAX(ContentHandler contentHandler, String tagName, Object value, Locale locale) throws SAXException 096 { 097 if (value != null) 098 { 099 if (value instanceof String) 100 { 101 ExplorerFile file = new ExplorerFile(_resolver, (String) value); 102 ResourceElementTypeHelper.singleFileToSAX(contentHandler, tagName, file, __EXPLORER_FILE_TYPE); 103 } 104 else if (value instanceof String[]) 105 { 106 for (String fileId : (String[]) value) 107 { 108 ExplorerFile file = new ExplorerFile(_resolver, fileId); 109 ResourceElementTypeHelper.singleFileToSAX(contentHandler, tagName, file, __EXPLORER_FILE_TYPE); 110 } 111 } 112 else if (value instanceof ExplorerFile) 113 { 114 ResourceElementTypeHelper.singleFileToSAX(contentHandler, tagName, (ExplorerFile) value, __EXPLORER_FILE_TYPE); 115 } 116 else if (value instanceof ExplorerFile[]) 117 { 118 for (ExplorerFile file : (ExplorerFile[]) value) 119 { 120 ResourceElementTypeHelper.singleFileToSAX(contentHandler, tagName, file, __EXPLORER_FILE_TYPE); 121 } 122 } 123 else if (value instanceof Binary) 124 { 125 ResourceElementTypeHelper.singleFileToSAX(contentHandler, tagName, (Binary) value, _binaryType); 126 } 127 else if (value instanceof Binary[]) 128 { 129 for (Binary binary : (Binary[]) value) 130 { 131 ResourceElementTypeHelper.singleFileToSAX(contentHandler, tagName, binary, _binaryType); 132 } 133 } 134 else 135 { 136 throw new IllegalArgumentException("Try to sax the non file value '" + value + "' in tag name '" + tagName + "'"); 137 } 138 } 139 } 140 141 @Override 142 public File parseConfiguration(Configuration configuration) throws ConfigurationException 143 { 144 if (configuration != null) 145 { 146 String fileId = configuration.getAttribute("id", null); 147 if (StringUtils.isNotEmpty(fileId)) 148 { 149 return new ExplorerFile(_resolver, fileId); 150 } 151 } 152 153 return null; 154 } 155 156 @Override 157 public Object valueToJSONForClient(Object value) 158 { 159 if (value == null) 160 { 161 return value; 162 } 163 else if (value instanceof String) 164 { 165 ExplorerFile file = new ExplorerFile(_resolver, (String) value); 166 return ResourceElementTypeHelper.singleFileToJSON(file, __EXPLORER_FILE_TYPE); 167 } 168 else if (value instanceof String[]) 169 { 170 return Arrays.asList((String[]) value).stream() 171 .map(fileId -> new ExplorerFile(_resolver, fileId)) 172 .map(file -> ResourceElementTypeHelper.singleFileToJSON(file, __EXPLORER_FILE_TYPE)) 173 .collect(Collectors.toList()); 174 } 175 else if (value instanceof ExplorerFile) 176 { 177 return ResourceElementTypeHelper.singleFileToJSON((ExplorerFile) value, __EXPLORER_FILE_TYPE); 178 } 179 else if (value instanceof ExplorerFile[]) 180 { 181 return Arrays.asList((ExplorerFile[]) value).stream() 182 .map(file -> ResourceElementTypeHelper.singleFileToJSON(file, __EXPLORER_FILE_TYPE)) 183 .collect(Collectors.toList()); 184 } 185 else if (value instanceof Binary) 186 { 187 return ResourceElementTypeHelper.singleFileToJSON((Binary) value, _binaryType); 188 } 189 else if (value instanceof Binary[]) 190 { 191 return Arrays.asList((Binary[]) value).stream() 192 .map(file -> ResourceElementTypeHelper.singleFileToJSON(file, _binaryType)) 193 .collect(Collectors.toList()); 194 } 195 else 196 { 197 throw new IllegalArgumentException("Try to convert the non file value '" + value + "' to JSON"); 198 } 199 } 200 201 public Object fromJSONForClient(Object json) 202 { 203 if (json == null) 204 { 205 return json; 206 } 207 else if (json instanceof String) 208 { 209 return castValue((String) json); 210 } 211 // TODO NEWATTRIBUTEAPI_CONTENT: This implementation only manages json object as string containing explorer file id. Fix this implementation when needed to migrate the EditContentFunction 212 else if (json instanceof List) 213 { 214 @SuppressWarnings("unchecked") 215 List<String> jsonList = (List<String>) json; 216 List<File> fileList = new ArrayList<>(); 217 for (String singleJSON : jsonList) 218 { 219 fileList.add(castValue(singleJSON)); 220 } 221 return fileList.toArray(new ContentValue[fileList.size()]); 222 } 223 else 224 { 225 throw new IllegalArgumentException("Try to convert the non file time JSON object '" + json + "' into a file"); 226 } 227 } 228 229 public boolean isSimple() 230 { 231 return false; 232 } 233 234 /** 235 * Check if ametys objects exist with the given identifiers 236 * @param identifiers the identifiers 237 * @return <code>true</code> if ametys object exist for each identifier, <code>false</code> otherwise 238 */ 239 protected boolean _hasAmetysObjectsForIdentifiers(String... identifiers) 240 { 241 for (String identifier : identifiers) 242 { 243 // If there is at list one identifier that does not match an ametys object => return false 244 if (identifier.indexOf("://") < 0 || !_resolver.hasAmetysObjectForId(identifier)) 245 { 246 return false; 247 } 248 } 249 250 // All identifiers match an ametys object 251 return true; 252 } 253}