001/* 002 * Copyright 2018 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.io.IOException; 019import java.util.ArrayList; 020import java.util.List; 021import java.util.Map; 022import java.util.Optional; 023import java.util.function.Function; 024import java.util.stream.Stream; 025 026import javax.xml.transform.TransformerException; 027 028import org.apache.cocoon.xml.AttributesImpl; 029import org.apache.commons.lang3.StringUtils; 030import org.apache.commons.lang3.tuple.ImmutableTriple; 031import org.apache.commons.lang3.tuple.Triple; 032import org.w3c.dom.Element; 033import org.xml.sax.ContentHandler; 034import org.xml.sax.SAXException; 035 036import org.ametys.core.model.type.AbstractElementType; 037import org.ametys.core.model.type.ModelItemTypeHelper; 038import org.ametys.plugins.repository.metadata.MultilingualString; 039import org.ametys.plugins.repository.metadata.MultilingualStringHelper; 040import org.ametys.runtime.model.ViewItem; 041import org.ametys.runtime.model.compare.DataChangeType; 042import org.ametys.runtime.model.compare.DataChangeTypeDetail; 043import org.ametys.runtime.model.exception.BadItemTypeException; 044import org.ametys.runtime.model.type.DataContext; 045 046/** 047 * Abstract class for multilingual string type of elements 048 */ 049public abstract class AbstractMultilingualStringElementType extends AbstractElementType<MultilingualString> 050{ 051 @Override 052 public MultilingualString convertValue(Object value) 053 { 054 if (value instanceof String) 055 { 056 try 057 { 058 return MultilingualStringHelper.fromString((String) value); 059 } 060 catch (IllegalArgumentException e) 061 { 062 throw new BadItemTypeException("Unable to cast '" + value + "' to a multilingual string"); 063 } 064 } 065 066 return super.convertValue(value); 067 } 068 069 @Override 070 public String toString(MultilingualString value) 071 { 072 return MultilingualStringHelper.toString(value); 073 } 074 075 @SuppressWarnings("unchecked") 076 public Object fromJSONForClient(Object json) 077 { 078 if (json == null) 079 { 080 return json; 081 } 082 else if (json instanceof Map) 083 { 084 return MultilingualStringHelper.fromJSON((Map<String, Object>) json); 085 } 086 else if (json instanceof List) 087 { 088 List<MultilingualString> multilingualStrings = new ArrayList<>(); 089 for (Map<String, Object> singleJson : (List<Map<String, Object>>) json) 090 { 091 multilingualStrings.add(MultilingualStringHelper.fromJSON(singleJson)); 092 } 093 return multilingualStrings.toArray(new MultilingualString[multilingualStrings.size()]); 094 } 095 else 096 { 097 throw new IllegalArgumentException("Try to convert the non multilingual string JSON object '" + json + "' into a multilingual string"); 098 } 099 } 100 101 @Override 102 protected Object _singleValueToJSON(MultilingualString value, DataContext context) 103 { 104 return MultilingualStringHelper.toJson(value); 105 } 106 107 @Override 108 protected MultilingualString _singleValueFromXML(Element element, Optional<Object> additionalData) throws TransformerException, IOException 109 { 110 return MultilingualStringHelper.fromXML(element); 111 } 112 113 @Override 114 protected void _singleValueToSAX(ContentHandler contentHandler, String tagName, MultilingualString value, Optional<ViewItem> viewItem, DataContext context, AttributesImpl attributes) throws SAXException 115 { 116 MultilingualStringHelper.sax(contentHandler, tagName, value, attributes, context.getLocale()); 117 } 118 119 @Override 120 protected Stream<Triple<DataChangeType, DataChangeTypeDetail, String>> _compareMultipleValues(MultilingualString[] value1, MultilingualString[] value2) throws IOException 121 { 122 throw new UnsupportedOperationException("Unable to compare multiple values of type '" + getId() + "'"); 123 } 124 125 @Override 126 protected Stream<Triple<DataChangeType, DataChangeTypeDetail, String>> _compareSingleValues(MultilingualString value1, MultilingualString value2) throws IOException 127 { 128 if (ModelItemTypeHelper.areSingleObjectsBothNotNullAndDifferents(value1, value2)) 129 { 130 return Stream.of 131 ( 132 // Manages modified and removed strings 133 value1.getLocales() 134 .stream() 135 .map 136 ( 137 locale -> ModelItemTypeHelper.compareSingleStrings 138 ( 139 value1.getValue(locale), 140 value2.hasLocale(locale) ? value2.getValue(locale) : StringUtils.EMPTY, 141 locale.toString() 142 ) 143 ) 144 .filter(Optional::isPresent) 145 .map(Optional::get), 146 147 // Manages added strings 148 value2.getLocales() 149 .stream() 150 .filter(locale -> !value1.hasLocale(locale)) 151 .map(locale -> new ImmutableTriple<>(DataChangeType.ADDED, DataChangeTypeDetail.NONE, locale.toString())) 152 ) 153 .flatMap(Function.identity()); 154 } 155 else 156 { 157 return Stream.of(ModelItemTypeHelper.compareSingleObjects(value1, value2, StringUtils.EMPTY)) 158 .filter(Optional::isPresent) 159 .map(Optional::get); 160 } 161 } 162 163 public boolean isSimple() 164 { 165 return true; 166 } 167 168 @Override 169 protected boolean _useJSONForEdition() 170 { 171 return true; 172 } 173}