View Javadoc
1   /**
2    * This file Copyright (c) 2012-2016 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.api.app.launcherlayout;
35  
36  import info.magnolia.cms.security.User;
37  import info.magnolia.cms.security.operations.AccessDefinition;
38  import info.magnolia.config.registry.DefinitionProvider;
39  import info.magnolia.config.registry.Registry;
40  import info.magnolia.context.MgnlContext;
41  import info.magnolia.event.EventBus;
42  import info.magnolia.event.SystemEventBus;
43  import info.magnolia.i18nsystem.I18nizer;
44  import info.magnolia.ui.api.app.AppDescriptor;
45  import info.magnolia.ui.api.app.registry.AppDescriptorRegistry;
46  import info.magnolia.ui.api.app.registry.AppRegistryEvent;
47  import info.magnolia.ui.api.app.registry.AppRegistryEventHandler;
48  
49  import java.util.ArrayList;
50  import java.util.List;
51  import java.util.concurrent.atomic.AtomicReference;
52  
53  import javax.inject.Inject;
54  import javax.inject.Named;
55  import javax.inject.Provider;
56  import javax.inject.Singleton;
57  
58  import org.apache.commons.lang3.StringUtils;
59  import org.slf4j.Logger;
60  import org.slf4j.LoggerFactory;
61  
62  /**
63   * Default {@link AppLauncherLayoutManager} implementation.
64   */
65  @Singleton
66  public class AppLauncherLayoutManagerImpl implements AppLauncherLayoutManager {
67  
68      private final Logger log = LoggerFactory.getLogger(AppLauncherLayoutManagerImpl.class);
69  
70      private final AppDescriptorRegistry appDescriptorRegistry;
71  
72      private final EventBus systemEventBus;
73  
74      private final AtomicReference<AppLauncherLayoutDefinition> layoutDefinitionReference = new AtomicReference<AppLauncherLayoutDefinition>();
75  
76      private final Provider<I18nizer> i18nizerProvider;
77  
78      @Inject
79      public AppLauncherLayoutManagerImpl(AppDescriptorRegistry appDescriptorRegistry, @Named(SystemEventBus.NAME) EventBus systemEventBus, Provider<I18nizer> i18nizerProvider) {
80          this.appDescriptorRegistry = appDescriptorRegistry;
81          this.systemEventBus = systemEventBus;
82          this.i18nizerProvider = i18nizerProvider;
83  
84          /**
85           * Propagate events from {@link info.magnolia.ui.api.app.registry.AppDescriptorRegistry} to notify listeners
86           * that the layout has changed.
87           */
88          systemEventBus.addHandler(AppRegistryEvent.class, new AppRegistryEventHandler() {
89  
90              @Override
91              public void onAppRegistered(AppRegistryEvent event) {
92                  String name = event.getAppDescriptorMetadata().getName();
93                  log.debug("Got AppRegistryEvent." + event.getEventType() + " for app: " + name);
94                  sendChangedEvent();
95              }
96  
97              @Override
98              public void onAppReregistered(AppRegistryEvent event) {
99                  String name = event.getAppDescriptorMetadata().getName();
100                 log.debug("Got AppRegistryEvent." + event.getEventType() + " for app: " + name);
101                 sendChangedEvent();
102             }
103 
104             @Override
105             public void onAppUnregistered(AppRegistryEvent event) {
106                 String name = event.getAppDescriptorMetadata().getName();
107                 log.debug("Got AppRegistryEvent." + event.getEventType() + " for app: " + name);
108                 sendChangedEvent();
109             }
110         });
111     }
112 
113     @Deprecated
114     @Override
115     public AppLauncherLayout getLayoutForCurrentUser() {
116         return getLayoutForUser(MgnlContext.getUser());
117     }
118 
119     @Override
120     public AppLauncherLayout getLayoutForUser(User user) {
121         AppLauncherLayoutDefinition layoutDefinition = layoutDefinitionReference.get();
122         if (layoutDefinition == null) {
123             return new AppLauncherLayout();
124         }
125 
126         AppLauncherLayout layout = new AppLauncherLayout();
127         for (AppLauncherGroupDefinition groupDefinition : layoutDefinition.getGroups()) {
128 
129             if (!isGroupVisibleForUser(groupDefinition, user)) {
130                 continue;
131             }
132 
133             List<AppLauncherGroupEntry> entries = new ArrayList<AppLauncherGroupEntry>();
134             for (AppLauncherGroupEntryDefinition entryDefinition : groupDefinition.getApps()) {
135                 AppDescriptor appDescriptor;
136                 try {
137                     final DefinitionProvider<AppDescriptor> definitionProvider = appDescriptorRegistry.getProvider(entryDefinition.getName());
138                     if (!definitionProvider.isValid()) {
139                         // app-descriptor is not valid, won't add it to the launcher
140                         continue;
141                     }
142                     appDescriptor = i18nizerProvider.get().decorate(definitionProvider.get());
143                 } catch (Registry.NoSuchDefinitionException | IllegalStateException e) {
144                     log.warn(e.getMessage());
145                     continue;
146                 }
147 
148                 if (StringUtils.isBlank(appDescriptor.getLabel()) || StringUtils.isBlank(appDescriptor.getIcon())) {
149                     log.warn("Label and/or icon for app [{}] are blank. App won't be displayed in the app launcher. Please either define them in the configuration tree or in the app's i18n properties file.", entryDefinition.getName());
150                     continue;
151                 }
152 
153                 if (isAppVisibleForUser(entryDefinition, appDescriptor, user)) {
154                     AppLauncherGroupEntry entry = new AppLauncherGroupEntry();
155                     entry.setName(entryDefinition.getName());
156                     entry.setEnabled(entryDefinition.isEnabled());
157                     entry.setAppDescriptor(appDescriptor);
158                     entries.add(entry);
159                 }
160             }
161 
162             if (!entries.isEmpty()) {
163                 AppLauncherGroup group = new AppLauncherGroup();
164                 group.setName(groupDefinition.getName());
165                 group.setLabel(groupDefinition.getLabel());
166                 group.setColor(groupDefinition.getColor());
167                 group.setPermanent(groupDefinition.isPermanent());
168                 group.setClientGroup(groupDefinition.isClientGroup());
169                 group.setApps(entries);
170                 layout.addGroup(group);
171             }
172         }
173         return layout;
174     }
175 
176     @Override
177     public void setLayout(AppLauncherLayoutDefinition layout) {
178         this.layoutDefinitionReference.set(i18nizerProvider.get().decorate(layout));
179         sendChangedEvent();
180     }
181 
182     private boolean isAppVisibleForUser(AppLauncherGroupEntryDefinition entry, AppDescriptor appDescriptor, User user) {
183         AccessDefinition permissions = appDescriptor.getPermissions();
184         return entry.isEnabled() && appDescriptor.isEnabled() && (permissions == null || permissions.hasAccess(user));
185     }
186 
187     private boolean isGroupVisibleForUser(AppLauncherGroupDefinition group, User user) {
188         AccessDefinition permissions = group.getPermissions();
189         return (permissions == null || permissions.hasAccess(user));
190     }
191 
192     /**
193      * Sends an event on the system event bus.
194      */
195     private void sendChangedEvent() {
196         log.debug("Sending AppLauncherLayoutChangedEvent on the system bus");
197         systemEventBus.fireEvent(new AppLauncherLayoutChangedEvent());
198     }
199 }