View Javadoc
1   /**
2    * This file Copyright (c) 2013-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.framework;
35  
36  import info.magnolia.cms.security.operations.AccessDefinition;
37  import info.magnolia.config.source.ConfigurationSourceFactory;
38  import info.magnolia.config.source.yaml.YamlConfigurationSourceBuilder;
39  import info.magnolia.event.EventBus;
40  import info.magnolia.event.SystemEventBus;
41  import info.magnolia.i18nsystem.SimpleTranslator;
42  import info.magnolia.jcr.predicate.AbstractPredicate;
43  import info.magnolia.jcr.util.NodeUtil;
44  import info.magnolia.jcr.wrapper.ExtendingNodeWrapper;
45  import info.magnolia.module.ModuleLifecycle;
46  import info.magnolia.module.ModuleLifecycleContext;
47  import info.magnolia.module.ModuleRegistry;
48  import info.magnolia.objectfactory.Components;
49  import info.magnolia.types.datasource.jcr.WorkspaceInitializeEvent;
50  import info.magnolia.ui.api.app.registry.AppDescriptorRegistry;
51  import info.magnolia.ui.api.app.registry.DefinitionTypes;
52  import info.magnolia.ui.api.message.Message;
53  import info.magnolia.ui.api.message.MessageType;
54  import info.magnolia.ui.dialog.DialogDefinitionRegistry;
55  import info.magnolia.ui.dialog.definition.ConfiguredFormDialogDefinition;
56  import info.magnolia.ui.form.fieldtype.registry.FieldTypeDefinitionRegistry;
57  import info.magnolia.ui.framework.app.contenttypes.AppWithContentType;
58  import info.magnolia.ui.framework.message.MessagesManager;
59  
60  
61  import javax.inject.Inject;
62  import javax.inject.Named;
63  import javax.jcr.Node;
64  import javax.jcr.RepositoryException;
65  
66  import lombok.SneakyThrows;
67  
68  /**
69   * Module class for UI framework.
70   */
71  public class UiFrameworkCompatibilityModule implements ModuleLifecycle {
72  
73      private final ConfigurationSourceFactory configSourceFactory;
74      private final FieldTypeDefinitionRegistry fieldTypeDefinitionRegistry;
75      private final DialogDefinitionRegistry dialogDefinitionRegistry;
76      private final AppDescriptorRegistry appDescriptorRegistry;
77      private final ModuleRegistry moduleRegistry;
78      private final EventBus eventBus;
79      private final MessagesManager messagesManager;
80      private final SimpleTranslator i18n;
81  
82      @Inject
83      public UiFrameworkCompatibilityModule(ConfigurationSourceFactory configSourceFactory,
84                                            FieldTypeDefinitionRegistry fieldTypeDefinitionRegistry,
85                                            DialogDefinitionRegistry dialogDefinitionRegistry,
86                                            AppDescriptorRegistry appDescriptorRegistry,
87                                            ModuleRegistry moduleRegistry,
88                                            @Named(SystemEventBus.NAME) EventBus eventBus,
89                                            MessagesManager messagesManager,
90                                            SimpleTranslator i18n) {
91  
92          this.configSourceFactory = configSourceFactory;
93          this.fieldTypeDefinitionRegistry = fieldTypeDefinitionRegistry;
94          this.dialogDefinitionRegistry = dialogDefinitionRegistry;
95          this.appDescriptorRegistry = appDescriptorRegistry;
96          this.moduleRegistry = moduleRegistry;
97          this.eventBus = eventBus;
98          this.messagesManager = messagesManager;
99          this.i18n = i18n;
100     }
101 
102     @Override
103     public void start(ModuleLifecycleContext context) {
104         if (context.getPhase() == ModuleLifecycleContext.PHASE_SYSTEM_STARTUP) {
105 
106             /**
107              * TODO Address loading order of these registries because of validators in MGNLUI-4770.
108              * Dialog registry is temporarily moved after field type registry because dialogs depend on field types
109              * to be perfectly built.
110              */
111             configSourceFactory.jcr().withFilter(new IsFieldType()).bindWithDefaults(fieldTypeDefinitionRegistry);
112             configSourceFactory.yaml().bindWithDefaults(fieldTypeDefinitionRegistry);
113 
114             configSourceFactory.jcr().withFilter(new IsDialogNode()).bindWithDefaults(dialogDefinitionRegistry);
115             configSourceFactory.yaml().bindWithDefaults(dialogDefinitionRegistry);
116 
117             configSourceFactory.jcr().withFilter(new IsAppDescriptor()).bindWithDefaults(appDescriptorRegistry);
118             YamlConfigurationSourceBuilder appConfigurationSource = configSourceFactory.yaml();
119             if (moduleRegistry.isModuleRegistered("content-types")) {
120                 appConfigurationSource.withCustomMultiConstruct(AppWithContentType.TAG_PREFIX, problemCollector -> Components.newInstance(AppWithContentType.class, problemCollector));
121                 eventBus.addHandler(WorkspaceInitializeEvent.class, event -> {
122                     // i18n here will use system preferred language not user one, because this comes from background thread
123                     Message message = new Message(MessageType.INFO, i18n.translate("content-type.workspace.initialized.subject", event.getWorkspace()), i18n.translate("content-type.workspace.initialized.message", event.getWorkspace()));
124                     message.setSender("system");
125                     messagesManager.sendRoleMessage(AccessDefinition.DEFAULT_SUPERUSER_ROLE, message);
126                 });
127             }
128 
129             appConfigurationSource.bindWithDefaults(appDescriptorRegistry);
130         }
131     }
132 
133     @Override
134     public void stop(ModuleLifecycleContext context) {
135     }
136 
137     /**
138      * Check if this node can be handled as an {@link info.magnolia.ui.api.app.AppDescriptor}.
139      * Prior to 5.4, this was in {@link info.magnolia.ui.api.app.registry.ConfiguredAppDescriptorManager}.
140      */
141     private static class IsAppDescriptor extends AbstractPredicate<Node> {
142         @Override
143         public boolean evaluateTyped(Node node) {
144             try {
145                 if (node.hasProperty(ConfiguredFormDialogDefinition.EXTEND_PROPERTY_NAME)) {
146                     node = new ExtendingNodeWrapper(node);
147                 }
148                 return DefinitionTypes.APP.getPluralName().equalsIgnoreCase(node.getParent().getName());
149             } catch (RepositoryException e) {
150                 throw new RuntimeException(e);
151             }
152         }
153     }
154 
155     /**
156      * Check if this node can be handled as an {@link info.magnolia.ui.form.fieldtype.definition.FieldTypeDefinition}.
157      * Prior to 5.4, this was in {@link info.magnolia.ui.form.fieldtype.registry.ConfiguredFieldTypeDefinitionManager}.
158      */
159     private static class IsFieldType extends AbstractPredicate<Node> {
160 
161         public static final String DEFINITION_CLASS = "definitionClass";
162 
163         public static final String FACTORY_CLASS = "factoryClass";
164 
165         @Override
166         public boolean evaluateTyped(Node node) {
167             try {
168                 if (node.hasProperty(ConfiguredFormDialogDefinition.EXTEND_PROPERTY_NAME)) {
169                     node = new ExtendingNodeWrapper(node);
170                 }
171                 return node.hasProperty(DEFINITION_CLASS) && node.hasProperty(FACTORY_CLASS);
172             } catch (RepositoryException e) {
173                 throw new RuntimeException(e);
174             }
175         }
176     }
177 
178     /**
179      * Check if this node can be handled as a dialog.
180      */
181     public static class IsDialogNode extends AbstractPredicate<Node> {
182         @SneakyThrows(RepositoryException.class)
183         @Override
184         public boolean evaluateTyped(Node node) {
185             if (node.hasProperty("extends") && !NodeUtil.isWrappedWith(node, ExtendingNodeWrapper.class)) {
186                 node = new ExtendingNodeWrapper(node);
187             }
188             return node.hasNode("form") || node.hasNode("actions");
189         }
190     }
191 }