1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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.DefinitionMetadata;
39 import info.magnolia.config.registry.DefinitionProvider;
40 import info.magnolia.config.registry.Registry;
41 import info.magnolia.context.MgnlContext;
42 import info.magnolia.event.EventBus;
43 import info.magnolia.event.SystemEventBus;
44 import info.magnolia.i18nsystem.I18nizer;
45 import info.magnolia.ui.api.app.AppDescriptor;
46 import info.magnolia.ui.api.app.registry.AppDescriptorRegistry;
47 import info.magnolia.ui.api.app.registry.AppRegistryEvent;
48 import info.magnolia.ui.api.app.registry.AppRegistryEventHandler;
49
50 import java.util.ArrayList;
51 import java.util.Collection;
52 import java.util.List;
53 import java.util.Optional;
54 import java.util.concurrent.atomic.AtomicReference;
55 import java.util.stream.Collectors;
56
57 import javax.inject.Inject;
58 import javax.inject.Named;
59 import javax.inject.Provider;
60 import javax.inject.Singleton;
61
62 import org.apache.commons.lang3.StringUtils;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66
67
68
69 @Singleton
70 public class AppLauncherLayoutManagerImpl implements AppLauncherLayoutManager {
71
72 private final Logger log = LoggerFactory.getLogger(AppLauncherLayoutManagerImpl.class);
73
74 private final AppDescriptorRegistry appDescriptorRegistry;
75
76 private final EventBus systemEventBus;
77
78 private final AtomicReference<AppLauncherLayoutDefinition> layoutDefinitionReference = new AtomicReference<AppLauncherLayoutDefinition>();
79
80 private final Provider<I18nizer> i18nizerProvider;
81
82 @Inject
83 public AppLauncherLayoutManagerImpl(AppDescriptorRegistry appDescriptorRegistry, @Named(SystemEventBus.NAME) EventBus systemEventBus, Provider<I18nizer> i18nizerProvider) {
84 this.appDescriptorRegistry = appDescriptorRegistry;
85 this.systemEventBus = systemEventBus;
86 this.i18nizerProvider = i18nizerProvider;
87
88
89
90
91
92 systemEventBus.addHandler(AppRegistryEvent.class, new AppRegistryEventHandler() {
93
94 @Override
95 public void onAppRegistered(AppRegistryEvent event) {
96 logAndSendChangedEvent(event);
97 }
98
99 @Override
100 public void onAppReregistered(AppRegistryEvent event) {
101 logAndSendChangedEvent(event);
102 }
103
104 @Override
105 public void onAppUnregistered(AppRegistryEvent event) {
106 logAndSendChangedEvent(event);
107 }
108
109
110
111
112 private void logAndSendChangedEvent(AppRegistryEvent event) {
113 String name = event.getAppDescriptorMetadata().getName();
114 log.debug("Got AppRegistryEvent." + event.getEventType() + " for app: " + name);
115 systemEventBus.fireEvent(new AppLauncherLayoutChangedEvent());
116 log.debug("Sending AppLauncherLayoutChangedEvent on the system bus");
117 }
118 });
119 }
120
121 @Deprecated
122 @Override
123 public AppLauncherLayout getLayoutForCurrentUser() {
124 return getLayoutForUser(MgnlContext.getUser());
125 }
126
127 @Override
128 public AppLauncherLayout getLayoutForUser(User user) {
129
130 AppLauncherLayoutDefinition layoutDefinition = layoutDefinitionReference.get();
131 if (layoutDefinition == null) {
132 return new AppLauncherLayout();
133 }
134
135 Optional<AppLauncherGroup> defaultGroup = Optional.empty();
136 Collection<String> processedApps = new ArrayList<>();
137
138 AppLauncherLayout layout = new AppLauncherLayout();
139 for (AppLauncherGroupDefinition groupDefinition : layoutDefinition.getGroups()) {
140 if (!isGroupVisibleForUser(groupDefinition, user)) {
141 processedApps.addAll(groupDefinition.getApps().stream().map(AppLauncherGroupEntryDefinition::getName).collect(Collectors.toList()));
142 continue;
143 }
144
145 List<AppLauncherGroupEntry> entries = new ArrayList<>();
146 for (AppLauncherGroupEntryDefinition entryDefinition : groupDefinition.getApps()) {
147 processedApps.add(entryDefinition.getName());
148 final Optional<AppDescriptor> appDescriptor = getAppDescriptor(entryDefinition.getName());
149 if (!appDescriptor.isPresent() || layoutDefinition.getHiddenApps().contains(appDescriptor.get().getName()) || !isAppVisibleForUser(entryDefinition, appDescriptor.get(), user)) {
150 continue;
151 }
152 entries.add(createAppEntry(entryDefinition, appDescriptor.get()));
153 }
154
155 if (!entries.isEmpty() || groupDefinition.getName().equals(layoutDefinition.getDefaultGroup())) {
156 AppLauncherGroup group = new AppLauncherGroup();
157 group.setName(groupDefinition.getName());
158 group.setLabel(groupDefinition.getLabel());
159 group.setColor(groupDefinition.getColor());
160 group.setPermanent(groupDefinition.isPermanent());
161 group.setClientGroup(groupDefinition.isClientGroup());
162 group.setApps(entries);
163 layout.addGroup(group);
164
165 if (groupDefinition.getName().equals(layoutDefinition.getDefaultGroup())) {
166 defaultGroup = Optional.of(group);
167 }
168 }
169 }
170
171 final List<String> unprocessedApps = appDescriptorRegistry.getAllMetadata().stream()
172 .map(DefinitionMetadata::getName)
173 .filter(entry -> !processedApps.contains(entry) && !layoutDefinition.getHiddenApps().contains(entry))
174 .collect(Collectors.toList());
175
176 if (layoutDefinition.getDefaultGroup() != null && !defaultGroup.isPresent()) {
177 log.debug("Configured default group ({}={}) doesn't exist or user doesn't have permission for it.", "config:/modules/ui-admincentral/config/appLauncherLayout@defaultGroup", layoutDefinition.getDefaultGroup());
178 }
179
180 if (defaultGroup.isPresent()) {
181 for (String appName : unprocessedApps) {
182 final Optional<AppDescriptor> appDescriptor = getAppDescriptor(appName);
183 if (appDescriptor.isPresent()) {
184 final ConfiguredAppLauncherGroupEntryDefinition appLauncherGroupEntryDefinition = new ConfiguredAppLauncherGroupEntryDefinition();
185 appLauncherGroupEntryDefinition.setName(appName);
186 if (isAppVisibleForUser(appLauncherGroupEntryDefinition, appDescriptor.get(), user)) {
187 defaultGroup.get().getApps().add( createAppEntry(appLauncherGroupEntryDefinition, appDescriptor.get()));
188 log.debug("App {{}} is not registered in the applauncher. Adding it to the default applauncher group {{}}", appName, defaultGroup.get().getName());
189 }
190 }
191 }
192 } else if (!unprocessedApps.isEmpty()) {
193 log.debug("Apps {} are not registered in the applauncher. Configure a default group (at {}) where to add unregistered apps automatically.", unprocessedApps, "config:/modules/ui-admincentral/config/appLauncherLayout@defaultGroup");
194 }
195 return layout;
196 }
197
198 @Override
199 public void setLayout(AppLauncherLayoutDefinition layout) {
200 this.layoutDefinitionReference.set(i18nizerProvider.get().decorate(layout));
201 log.debug("Sending AppLauncherLayoutChangedEvent on the system bus");
202 systemEventBus.fireEvent(new AppLauncherLayoutChangedEvent());
203 }
204
205 private AppLauncherGroupEntry createAppEntry(AppLauncherGroupEntryDefinition entryDefinition, AppDescriptor appDescriptor) {
206 AppLauncherGroupEntry entry = new AppLauncherGroupEntry();
207 entry.setName(entryDefinition.getName());
208 entry.setEnabled(entryDefinition.isEnabled());
209 entry.setAppDescriptor(appDescriptor);
210 return entry;
211 }
212
213 private Optional<AppDescriptor> getAppDescriptor(String appName) {
214 try {
215 final DefinitionProvider<AppDescriptor> definitionProvider = appDescriptorRegistry.getProvider(appName);
216 if (definitionProvider.isValid()) {
217 AppDescriptor appDescriptor = i18nizerProvider.get().decorate(definitionProvider.get());
218 if (StringUtils.isBlank(appDescriptor.getLabel()) || StringUtils.isBlank(appDescriptor.getIcon())) {
219 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.", appName);
220 } else {
221 return Optional.of(appDescriptor);
222 }
223 }
224 } catch (Registry.NoSuchDefinitionException e) {
225 log.warn("Definition not found: {}", e.getMessage());
226 } catch (IllegalStateException e) {
227 log.warn("Encountered IllegalStateException while getting appDescriptor: ", e.getMessage(), e);
228 }
229 return Optional.empty();
230 }
231
232 private boolean isAppVisibleForUser(AppLauncherGroupEntryDefinition entry, AppDescriptor appDescriptor, User user) {
233 AccessDefinition permissions = appDescriptor.getPermissions();
234 return entry.isEnabled() && appDescriptor.isEnabled() && (permissions == null || permissions.hasAccess(user));
235 }
236
237 private boolean isGroupVisibleForUser(AppLauncherGroupDefinition group, User user) {
238 AccessDefinition permissions = group.getPermissions();
239 return (permissions == null || permissions.hasAccess(user));
240 }
241 }