View Javadoc
1   /**
2    * This file Copyright (c) 2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.ui.form.definition;
35  
36  import info.magnolia.dynamic.MagnoliaProxy;
37  import info.magnolia.ui.api.action.ActionDefinition;
38  import info.magnolia.ui.api.action.ConfiguredActionDefinition;
39  import info.magnolia.ui.contentapp.action.CloseActionDefinition;
40  import info.magnolia.ui.contentapp.action.CommitActionDefinition;
41  import info.magnolia.ui.dialog.ConfiguredFormDialogDefinition;
42  import info.magnolia.ui.dialog.DialogDefinition;
43  import info.magnolia.ui.dialog.action.CancelDialogActionDefinition;
44  import info.magnolia.ui.dialog.action.SaveDialogActionDefinition;
45  import info.magnolia.ui.field.ConfiguredNamedFieldDefinition;
46  import info.magnolia.ui.field.EditorPropertyDefinition;
47  import info.magnolia.ui.field.NamedFieldDefinition;
48  import info.magnolia.ui.editor.ConfiguredFormDefinition;
49  import info.magnolia.ui.editor.FormDefinition;
50  import info.magnolia.ui.form.action.CancelFormActionDefinition;
51  import info.magnolia.ui.form.action.SaveFormActionDefinition;
52  import info.magnolia.ui.form.field.definition.BasicTextCodeFieldDefinition;
53  import info.magnolia.ui.form.field.definition.BasicUploadFieldDefinition;
54  import info.magnolia.ui.form.field.definition.CheckboxFieldDefinition;
55  import info.magnolia.ui.form.field.definition.CodeFieldDefinition;
56  import info.magnolia.ui.form.field.definition.CompositeFieldDefinition;
57  import info.magnolia.ui.form.field.definition.DateFieldDefinition;
58  import info.magnolia.ui.form.field.definition.HiddenFieldDefinition;
59  import info.magnolia.ui.form.field.definition.LinkFieldDefinition;
60  import info.magnolia.ui.form.field.definition.MultiValueFieldDefinition;
61  import info.magnolia.ui.form.field.definition.OptionGroupFieldDefinition;
62  import info.magnolia.ui.form.field.definition.RichTextFieldDefinition;
63  import info.magnolia.ui.form.field.definition.SelectFieldDefinition;
64  import info.magnolia.ui.form.field.definition.StaticFieldDefinition;
65  import info.magnolia.ui.form.field.definition.SwitchableFieldDefinition;
66  import info.magnolia.ui.form.field.definition.TextFieldDefinition;
67  import info.magnolia.ui.form.field.definition.TwinColSelectFieldDefinition;
68  import info.magnolia.ui.form.field.definition.migration.CheckboxFieldDefinitionConverter;
69  import info.magnolia.ui.form.field.definition.migration.CodeFieldDefinitionConverter;
70  import info.magnolia.ui.form.field.definition.migration.CompositeFieldDefinitionConverter;
71  import info.magnolia.ui.form.field.definition.migration.DateFieldDefinitionConverter;
72  import info.magnolia.ui.form.field.definition.migration.FieldDefinitionConverter;
73  import info.magnolia.ui.form.field.definition.migration.FallbackFieldDefinitionConverter;
74  import info.magnolia.ui.form.field.definition.migration.HiddenFieldDefinitionConverter;
75  import info.magnolia.ui.form.field.definition.migration.LinkFieldDefinitionConverter;
76  import info.magnolia.ui.form.field.definition.migration.MultiValueFieldDefinitionConverter;
77  import info.magnolia.ui.form.field.definition.migration.OptionGroupFieldDefinitionConverter;
78  import info.magnolia.ui.form.field.definition.migration.RichTextFieldDefinitionConverter;
79  import info.magnolia.ui.form.field.definition.migration.SelectFieldDefinitionConverter;
80  import info.magnolia.ui.form.field.definition.migration.StaticFieldDefinitionConverter;
81  import info.magnolia.ui.form.field.definition.migration.SwitchableFieldDefinitionConverter;
82  import info.magnolia.ui.form.field.definition.migration.TextFieldDefinitionConverter;
83  import info.magnolia.ui.form.field.definition.migration.TwinColSelectFieldDefinitionConverter;
84  import info.magnolia.ui.form.field.definition.migration.BasicUploadFieldDefinitionConverter;
85  import info.magnolia.ui.framework.layout.ConfiguredTabDefinition;
86  import info.magnolia.ui.framework.layout.TabDefinition;
87  import info.magnolia.ui.framework.layout.TabbedLayoutDefinition;
88  
89  import java.util.HashMap;
90  import java.util.HashSet;
91  import java.util.List;
92  import java.util.Map;
93  import java.util.Optional;
94  import java.util.Set;
95  import java.util.stream.Collectors;
96  
97  import org.apache.commons.collections4.CollectionUtils;
98  import org.slf4j.Logger;
99  import org.slf4j.LoggerFactory;
100 
101 import net.sf.cglib.proxy.Enhancer;
102 
103 /**
104  * Functional interface for definition converters.
105  *
106  * @param <OLD> - old definition class
107  * @param <NEW> - new definition class
108  *
109  * @deprecated since 6.2.1 - for compatibility use only.
110  */
111 @Deprecated
112 @FunctionalInterface
113 public interface DefinitionConverter<OLD, NEW> {
114 
115     Logger log = LoggerFactory.getLogger(DefinitionConverter.class);
116 
117     NEW convert(OLD definition);
118 
119     Map<Class<? extends info.magnolia.ui.form.field.definition.FieldDefinition>, FieldDefinitionConverter> FIELD_DEFINITION_CONVERTERS = new HashMap<Class<? extends info.magnolia.ui.form.field.definition.FieldDefinition>, FieldDefinitionConverter>() {{
120         put(TextFieldDefinition.class, new TextFieldDefinitionConverter());
121         put(StaticFieldDefinition.class, new StaticFieldDefinitionConverter());
122         put(HiddenFieldDefinition.class, new HiddenFieldDefinitionConverter());
123         put(CodeFieldDefinition.class, new CodeFieldDefinitionConverter());
124         put(BasicTextCodeFieldDefinition.class, new CodeFieldDefinitionConverter());
125         put(CheckboxFieldDefinition.class, new CheckboxFieldDefinitionConverter());
126         put(RichTextFieldDefinition.class, new RichTextFieldDefinitionConverter());
127         put(DateFieldDefinition.class, new DateFieldDefinitionConverter());
128         put(LinkFieldDefinition.class, new LinkFieldDefinitionConverter());
129         put(SelectFieldDefinition.class, new SelectFieldDefinitionConverter());
130         put(OptionGroupFieldDefinition.class, new OptionGroupFieldDefinitionConverter());
131         put(TwinColSelectFieldDefinition.class, new TwinColSelectFieldDefinitionConverter());
132         put(BasicUploadFieldDefinition.class, new BasicUploadFieldDefinitionConverter());
133         put(SwitchableFieldDefinition.class, new SwitchableFieldDefinitionConverter());
134         put(CompositeFieldDefinition.class, new CompositeFieldDefinitionConverter());
135         put(MultiValueFieldDefinition.class, new MultiValueFieldDefinitionConverter());
136     }};
137 
138     DefinitionConverter<info.magnolia.ui.form.field.definition.FieldDefinition, NamedFieldDefinition> NAMED = (oldDefinition) -> {
139         ConfiguredNamedFieldDefinition namedDefinition = new ConfiguredNamedFieldDefinition();
140         namedDefinition.setName(oldDefinition instanceof BasicUploadFieldDefinition ?
141                 ((BasicUploadFieldDefinition) oldDefinition).getBinaryNodeName() :
142                 oldDefinition.getName());
143         return namedDefinition;
144     };
145 
146     DefinitionConverter<info.magnolia.ui.form.definition.TabDefinition, TabDefinition> TAB = (oldDefinition) -> {
147         ConfiguredTabDefinitioninition.html#ConfiguredTabDefinition">ConfiguredTabDefinition newDefinition = new ConfiguredTabDefinition();
148         newDefinition.setLabel(oldDefinition.getLabel());
149         newDefinition.setName(oldDefinition.getName());
150         newDefinition.setFields(oldDefinition.getFields().stream().map(NAMED::convert).collect(Collectors.toList()));
151         return newDefinition;
152     };
153 
154     DefinitionConverter<info.magnolia.ui.form.field.definition.FieldDefinition, EditorPropertyDefinition> FIELD = (oldDefinition) -> {
155         log.debug("Converting old framework field definition [{}] to new definition.", oldDefinition.getName());
156 
157         Class oldDefinitionClass = Enhancer.isEnhanced(oldDefinition.getClass()) || MagnoliaProxy.class.isAssignableFrom(oldDefinition.getClass())
158                 ? oldDefinition.getClass().getSuperclass() : oldDefinition.getClass();
159         FieldDefinitionConverter converter = Optional.of(oldDefinitionClass)
160                 .map(FIELD_DEFINITION_CONVERTERS::get)
161                 .filter(selectedConverter -> selectedConverter.supports(oldDefinition))
162                 .orElseGet(FallbackFieldDefinitionConverter::new);
163         return converter.convert(oldDefinition);
164     };
165 
166     DefinitionConverter<info.magnolia.ui.form.definition.FormDefinition, FormDefinition> FORM = (oldDefinition) -> {
167         TabbedLayoutDefinition tabbedLayoutDefinition = new TabbedLayoutDefinition();
168         tabbedLayoutDefinition.setTabs(oldDefinition.getTabs().stream()
169                 .filter(tabDefinition -> CollectionUtils.isNotEmpty(tabDefinition.getFields()))
170                 .map(TAB::convert)
171                 .collect(Collectors.toList()));
172         ConfiguredFormDefinition<?> newDefinition = new ConfiguredFormDefinition<>();
173         newDefinition.setName(oldDefinition.getLabel());
174         newDefinition.setLayout(tabbedLayoutDefinition);
175         //newDefinition.setImplementationClass();
176         final Set<String> fieldNames = new HashSet<>();
177         List<EditorPropertyDefinition> properties = oldDefinition
178                 .getTabs()
179                 .stream()
180                 .map(info.magnolia.ui.form.definition.TabDefinition::getFields)
181                 .flatMap(List::stream)
182                 .map(FIELD::convert)
183                 .filter(field -> {
184                     if (fieldNames.contains(field.getName())) {
185                         // old form definitions could have more than one (static) fields of the same name on different tabs
186                         log.warn("Removing field with non-unique name: " + field.getName());
187                         return false;
188                     }
189                     fieldNames.add(field.getName());
190                     return true;
191                 })
192                 .collect(Collectors.toList());
193 
194         newDefinition.setProperties(properties);
195         return newDefinition;
196     };
197 
198     DefinitionConverter<ActionDefinition, ActionDefinition> ACTION = (oldDefinition) -> {
199         log.debug("Converting old framework action definition [{}] to new definition.", oldDefinition.getName());
200         if (oldDefinition instanceof SaveFormActionDefinition || oldDefinition instanceof SaveDialogActionDefinition) {
201             return withOldActionDefinitionProperties(new CommitActionDefinition(), oldDefinition);
202         } else if (oldDefinition instanceof CancelDialogActionDefinition || oldDefinition instanceof CancelFormActionDefinition) {
203             return withOldActionDefinitionProperties(new CloseActionDefinition(), oldDefinition);
204         } else {
205             final ConfiguredActionDefinition configuredActionDefinition = new ConfiguredActionDefinition();
206             configuredActionDefinition.setName("Unsupported action");
207             configuredActionDefinition.setDescription("Please migrate to new framework dialog");
208             return configuredActionDefinition;
209         }
210     };
211 
212     static ActionDefinition withOldActionDefinitionProperties(CloseActionDefinition newDefinition, ActionDefinition oldDefinition) {
213         newDefinition.setLabel(oldDefinition.getLabel());
214         newDefinition.setIcon(oldDefinition.getIcon());
215         newDefinition.setDescription(oldDefinition.getDescription());
216         newDefinition.setErrorMessage(oldDefinition.getErrorMessage());
217         newDefinition.setFailureMessage(oldDefinition.getFailureMessage());
218         newDefinition.setSuccessMessage(oldDefinition.getSuccessMessage());
219         return newDefinition;
220     }
221 
222     DefinitionConverter<info.magnolia.ui.dialog.definition.FormDialogDefinition, DialogDefinition> DIALOG = (oldDefinition) -> {
223         log.debug("Converting old framework dialog definition [{}] to new definition.",oldDefinition.getId());
224         ConfiguredFormDialogDefinition<Object> newDefinition = new ConfiguredFormDialogDefinition<>();
225         final FormDefinition<Object> convert = FORM.convert(oldDefinition.getForm());
226         String i18nLabel = Optional.ofNullable(oldDefinition.getLabel())
227                 .filter(DefinitionConverter::isNotMessageKey)
228                 .orElse(oldDefinition.getForm().getLabel());
229 
230         i18nLabel = Optional.ofNullable(i18nLabel).filter(DefinitionConverter::isNotMessageKey).orElse("");
231 
232         newDefinition.setLabel(i18nLabel);
233         newDefinition.setId(oldDefinition.getId());
234         newDefinition.setWide(oldDefinition.isWide());
235         newDefinition.setLight(oldDefinition.isLight());
236         newDefinition.setForm(convert);
237         newDefinition.setActions(oldDefinition.getActions().entrySet().stream()
238                 .collect(Collectors.toMap(Map.Entry::getKey, entry -> ACTION.convert(entry.getValue())))
239         );
240         return newDefinition;
241     };
242 
243     /**
244      * @deprecated is a hack and should not be used. See MGNLUI-2207.
245      */
246     @Deprecated
247     static boolean isNotMessageKey(final String text) {
248         return text.contains(" ") || !text.contains(".") || text.endsWith(".");
249     }
250 }