1 package org
.argeo
.app
.ui
;
3 import static org
.argeo
.api
.cms
.CmsView
.CMS_VIEW_UID_PROPERTY
;
5 import java
.util
.Collections
;
6 import java
.util
.HashMap
;
7 import java
.util
.HashSet
;
9 import java
.util
.Locale
;
11 import java
.util
.Objects
;
13 import java
.util
.TreeMap
;
14 import java
.util
.TreeSet
;
16 import javax
.jcr
.Node
;
17 import javax
.jcr
.Repository
;
18 import javax
.jcr
.RepositoryException
;
19 import javax
.jcr
.Session
;
20 import javax
.jcr
.nodetype
.NodeType
;
21 import javax
.naming
.InvalidNameException
;
22 import javax
.naming
.ldap
.LdapName
;
24 import org
.argeo
.api
.cms
.CmsSession
;
25 import org
.argeo
.api
.cms
.CmsTheme
;
26 import org
.argeo
.api
.cms
.CmsUi
;
27 import org
.argeo
.api
.cms
.CmsView
;
28 import org
.argeo
.app
.api
.EntityConstants
;
29 import org
.argeo
.app
.api
.EntityNames
;
30 import org
.argeo
.app
.api
.EntityType
;
31 import org
.argeo
.app
.api
.RankedObject
;
32 import org
.argeo
.app
.core
.SuiteUtils
;
33 import org
.argeo
.api
.cms
.CmsLog
;
34 import org
.argeo
.cms
.AbstractCmsApp
;
35 import org
.argeo
.cms
.CmsUserManager
;
36 import org
.argeo
.cms
.LocaleUtils
;
37 import org
.argeo
.cms
.Localized
;
38 import org
.argeo
.cms
.jcr
.CmsJcrUtils
;
39 import org
.argeo
.cms
.swt
.CmsSwtUtils
;
40 import org
.argeo
.cms
.swt
.dialogs
.CmsFeedback
;
41 import org
.argeo
.cms
.ui
.CmsUiProvider
;
42 import org
.argeo
.eclipse
.ui
.specific
.UiContext
;
43 import org
.argeo
.jcr
.Jcr
;
44 import org
.argeo
.jcr
.JcrException
;
45 import org
.argeo
.util
.LangUtils
;
46 import org
.eclipse
.swt
.SWT
;
47 import org
.eclipse
.swt
.widgets
.Composite
;
48 import org
.osgi
.framework
.Constants
;
49 import org
.osgi
.service
.event
.Event
;
50 import org
.osgi
.service
.event
.EventHandler
;
51 import org
.osgi
.service
.useradmin
.User
;
53 /** The Argeo Suite App. */
54 public class SuiteApp
extends AbstractCmsApp
implements EventHandler
{
55 private final static CmsLog log
= CmsLog
.getLog(SuiteApp
.class);
57 public final static String PUBLIC_BASE_PATH_PROPERTY
= "publicBasePath";
58 public final static String DEFAULT_UI_NAME_PROPERTY
= "defaultUiName";
59 public final static String DEFAULT_THEME_ID_PROPERTY
= "defaultThemeId";
60 public final static String DEFAULT_LAYER_PROPERTY
= "defaultLayer";
61 private final static String LOGIN
= "login";
62 private final static String HOME_STATE
= "~";
64 private String publicBasePath
= null;
66 private String pidPrefix
;
67 private String headerPid
;
68 private String footerPid
;
69 private String leadPanePid
;
70 private String adminLeadPanePid
;
71 private String loginScreenPid
;
73 private String defaultUiName
= "app";
74 private String adminUiName
= "admin";
76 // FIXME such default names make refactoring more dangerous
78 private String defaultLayerPid
= "argeo.suite.ui.dashboardLayer";
80 private String defaultThemeId
= "org.argeo.app.theme.default";
82 private Map
<String
, RankedObject
<CmsUiProvider
>> uiProvidersByPid
= Collections
.synchronizedMap(new HashMap
<>());
83 private Map
<String
, RankedObject
<CmsUiProvider
>> uiProvidersByType
= Collections
.synchronizedMap(new HashMap
<>());
84 private Map
<String
, RankedObject
<SuiteLayer
>> layersByPid
= Collections
.synchronizedSortedMap(new TreeMap
<>());
85 private Map
<String
, RankedObject
<SuiteLayer
>> layersByType
= Collections
.synchronizedSortedMap(new TreeMap
<>());
87 private CmsUserManager cmsUserManager
;
89 // TODO make more optimal or via CmsSession/CmsView
90 private Map
<String
, SuiteUi
> managedUis
= new HashMap
<>();
92 private Repository repository
;
94 public void init(Map
<String
, Object
> properties
) {
95 if (log
.isDebugEnabled())
96 log
.info("Argeo Suite App started");
98 if (properties
.containsKey(DEFAULT_UI_NAME_PROPERTY
))
99 defaultUiName
= LangUtils
.get(properties
, DEFAULT_UI_NAME_PROPERTY
);
100 if (properties
.containsKey(DEFAULT_THEME_ID_PROPERTY
))
101 defaultThemeId
= LangUtils
.get(properties
, DEFAULT_THEME_ID_PROPERTY
);
102 if (properties
.containsKey(DEFAULT_LAYER_PROPERTY
))
103 defaultLayerPid
= LangUtils
.get(properties
, DEFAULT_LAYER_PROPERTY
);
104 publicBasePath
= LangUtils
.get(properties
, PUBLIC_BASE_PATH_PROPERTY
);
106 if (properties
.containsKey(Constants
.SERVICE_PID
)) {
107 String servicePid
= properties
.get(Constants
.SERVICE_PID
).toString();
108 if (servicePid
.endsWith(".app")) {
109 pidPrefix
= servicePid
.substring(0, servicePid
.length() - "app".length());
113 if (pidPrefix
== null)
114 throw new IllegalArgumentException("PID prefix must be set.");
116 headerPid
= pidPrefix
+ "header";
117 footerPid
= pidPrefix
+ "footer";
118 leadPanePid
= pidPrefix
+ "leadPane";
119 adminLeadPanePid
= pidPrefix
+ "adminLeadPane";
120 loginScreenPid
= pidPrefix
+ "loginScreen";
123 public void destroy(Map
<String
, Object
> properties
) {
124 for (SuiteUi ui
: managedUis
.values())
125 if (!ui
.isDisposed()) {
126 ui
.getDisplay().syncExec(() -> ui
.dispose());
128 if (log
.isDebugEnabled())
129 log
.info("Argeo Suite App stopped");
134 public Set
<String
> getUiNames() {
135 HashSet
<String
> uiNames
= new HashSet
<>();
136 uiNames
.add(defaultUiName
);
137 uiNames
.add(adminUiName
);
142 public CmsUi
initUi(Object parent
) {
143 Composite uiParent
= (Composite
) parent
;
144 String uiName
= uiParent
.getData(UI_NAME_PROPERTY
) != null ? uiParent
.getData(UI_NAME_PROPERTY
).toString()
146 CmsView cmsView
= CmsSwtUtils
.getCmsView(uiParent
);
148 throw new IllegalStateException("No CMS view is registered.");
149 CmsTheme theme
= getTheme(uiName
);
151 CmsSwtUtils
.registerCmsTheme(uiParent
.getShell(), theme
);
152 SuiteUi argeoSuiteUi
= new SuiteUi(uiParent
, SWT
.INHERIT_DEFAULT
);
153 String uid
= cmsView
.getUid();
154 managedUis
.put(uid
, argeoSuiteUi
);
155 argeoSuiteUi
.addDisposeListener((e
) -> {
156 managedUis
.remove(uid
);
157 if (log
.isDebugEnabled())
158 log
.debug("Suite UI " + uid
+ " has been disposed.");
164 public String
getThemeId(String uiName
) {
165 String themeId
= System
.getProperty("org.argeo.app.theme.default");
168 return defaultThemeId
;
172 public void refreshUi(CmsUi cmsUi
, String state
) {
175 SuiteUi ui
= (SuiteUi
) cmsUi
;
177 String uiName
= Objects
.toString(ui
.getParent().getData(UI_NAME_PROPERTY
), null);
179 throw new IllegalStateException("UI name should not be null");
180 CmsView cmsView
= CmsSwtUtils
.getCmsView(ui
);
181 CmsUiProvider headerUiProvider
= findUiProvider(headerPid
);
182 CmsUiProvider footerUiProvider
= findUiProvider(footerPid
);
183 CmsUiProvider leadPaneUiProvider
;
184 if (adminUiName
.equals(uiName
)) {
185 leadPaneUiProvider
= findUiProvider(adminLeadPanePid
);
187 leadPaneUiProvider
= findUiProvider(leadPanePid
);
190 Localized appTitle
= null;
191 if (headerUiProvider
instanceof DefaultHeader
) {
192 appTitle
= ((DefaultHeader
) headerUiProvider
).getTitle();
194 ui
.setTitle(appTitle
);
196 if (cmsView
.isAnonymous() && publicBasePath
== null) {// internal app, must login
198 if (headerUiProvider
!= null)
199 refreshPart(headerUiProvider
, ui
.getHeader(), context
);
200 ui
.refreshBelowHeader(false);
201 refreshPart(findUiProvider(loginScreenPid
), ui
.getBelowHeader(), context
);
202 if (footerUiProvider
!= null)
203 refreshPart(footerUiProvider
, ui
.getFooter(), context
);
204 ui
.layout(true, true);
207 if (LOGIN
.equals(state
))
209 CmsSession cmsSession
= cmsView
.getCmsSession();
210 if (ui
.getUserDir() == null) {
211 // FIXME NPE on CMSSession when logging in from anonymous
212 if (cmsSession
== null || cmsView
.isAnonymous()) {
213 assert publicBasePath
!= null;
214 ui
.initSessions(getRepository(), publicBasePath
);
216 Session adminSession
= null;
218 adminSession
= CmsJcrUtils
.openDataAdminSession(getRepository(), null);
219 Node userDir
= SuiteUtils
.getOrCreateCmsSessionNode(adminSession
, cmsSession
);
220 ui
.initSessions(getRepository(), userDir
.getPath());
222 Jcr
.logout(adminSession
);
226 initLocale(cmsSession
);
227 context
= stateToNode(ui
, state
);
229 context
= ui
.getUserDir();
231 if (headerUiProvider
!= null)
232 refreshPart(headerUiProvider
, ui
.getHeader(), context
);
233 ui
.refreshBelowHeader(true);
234 for (String key
: layersByPid
.keySet()) {
235 SuiteLayer layer
= layersByPid
.get(key
).get();
236 ui
.addLayer(key
, layer
);
239 if (leadPaneUiProvider
!= null)
240 refreshPart(leadPaneUiProvider
, ui
.getLeadPane(), context
);
241 if (footerUiProvider
!= null)
242 refreshPart(footerUiProvider
, ui
.getFooter(), context
);
243 ui
.layout(true, true);
244 setState(ui
, state
!= null ? state
: defaultLayerPid
);
246 } catch (Exception e
) {
247 CmsFeedback
.show("Unexpected exception", e
);
251 private void initLocale(CmsSession cmsSession
) {
252 if (cmsSession
== null)
254 Locale locale
= cmsSession
.getLocale();
255 UiContext
.setLocale(locale
);
256 LocaleUtils
.setThreadLocale(locale
);
260 private void refreshPart(CmsUiProvider uiProvider
, Composite part
, Node context
) {
261 CmsSwtUtils
.clear(part
);
262 uiProvider
.createUiPart(part
, context
);
265 private CmsUiProvider
findUiProvider(String pid
) {
266 if (!uiProvidersByPid
.containsKey(pid
))
268 return uiProvidersByPid
.get(pid
).get();
271 private SuiteLayer
findLayer(String pid
) {
272 if (!layersByPid
.containsKey(pid
))
274 return layersByPid
.get(pid
).get();
277 private <T
> T
findByType(Map
<String
, RankedObject
<T
>> byType
, Node context
) {
279 throw new IllegalArgumentException("A node should be provided");
282 Set
<String
> types
= new TreeSet
<>();
283 for (NodeType mixinType
: context
.getMixinNodeTypes()) {
284 String mixinTypeName
= mixinType
.getName();
285 if (byType
.containsKey(mixinTypeName
)) {
286 types
.add(mixinTypeName
);
288 for (NodeType superType
: mixinType
.getDeclaredSupertypes()) {
289 if (byType
.containsKey(superType
.getName())) {
290 types
.add(superType
.getName());
295 NodeType primaryType
= context
.getPrimaryNodeType();
296 String primaryTypeName
= primaryType
.getName();
297 if (byType
.containsKey(primaryTypeName
)) {
298 types
.add(primaryTypeName
);
300 for (NodeType superType
: primaryType
.getDeclaredSupertypes()) {
301 if (byType
.containsKey(superType
.getName())) {
302 types
.add(superType
.getName());
306 if (context
.isNodeType(EntityType
.entity
.get())) {
307 if (context
.hasProperty(EntityNames
.ENTITY_TYPE
)) {
308 String entityTypeName
= context
.getProperty(EntityNames
.ENTITY_TYPE
).getString();
309 if (byType
.containsKey(entityTypeName
)) {
310 types
.add(entityTypeName
);
315 // if (context.getPath().equals("/")) {// root node
316 // types.add("nt:folder");
318 if (CmsJcrUtils
.isUserHome(context
) && byType
.containsKey("nt:folder")) {// home node
319 types
.add("nt:folder");
322 if (types
.size() == 0)
323 throw new IllegalArgumentException("No type found for " + context
+ " (" + listTypes(context
) + ")");
324 String type
= types
.iterator().next();
325 if (!byType
.containsKey(type
))
326 throw new IllegalArgumentException("No component found for " + context
+ " with type " + type
);
327 return byType
.get(type
).get();
328 } catch (RepositoryException e
) {
329 throw new IllegalStateException(e
);
333 private static String
listTypes(Node context
) {
335 StringBuilder sb
= new StringBuilder();
336 sb
.append(context
.getPrimaryNodeType().getName());
337 for (NodeType superType
: context
.getPrimaryNodeType().getDeclaredSupertypes()) {
339 sb
.append(superType
.getName());
342 for (NodeType nodeType
: context
.getMixinNodeTypes()) {
344 sb
.append(nodeType
.getName());
345 if (nodeType
.getName().equals(EntityType
.local
.get()))
346 sb
.append('/').append(context
.getProperty(EntityNames
.ENTITY_TYPE
).getString());
347 for (NodeType superType
: nodeType
.getDeclaredSupertypes()) {
349 sb
.append(superType
.getName());
352 return sb
.toString();
353 } catch (RepositoryException e
) {
354 throw new JcrException(e
);
359 public void setState(CmsUi cmsUi
, String state
) {
362 if (!state
.startsWith("/")) {
363 if (cmsUi
instanceof SuiteUi
) {
364 SuiteUi ui
= (SuiteUi
) cmsUi
;
365 if (LOGIN
.equals(state
)) {
366 String appTitle
= "";
367 if (ui
.getTitle() != null)
368 appTitle
= ui
.getTitle().lead();
369 ui
.getCmsView().stateChanged(state
, appTitle
);
372 Map
<String
, Object
> properties
= new HashMap
<>();
373 String layerId
= HOME_STATE
.equals(state
) ? defaultLayerPid
: state
;
374 properties
.put(SuiteEvent
.LAYER
, layerId
);
375 properties
.put(SuiteEvent
.NODE_PATH
, HOME_STATE
);
376 ui
.getCmsView().sendEvent(SuiteEvent
.switchLayer
.topic(), properties
);
380 SuiteUi suiteUi
= (SuiteUi
) cmsUi
;
381 Node node
= stateToNode(suiteUi
, state
);
383 suiteUi
.getCmsView().navigateTo(HOME_STATE
);
385 suiteUi
.getCmsView().sendEvent(SuiteEvent
.switchLayer
.topic(), SuiteEvent
.eventProperties(node
));
386 suiteUi
.getCmsView().sendEvent(SuiteEvent
.refreshPart
.topic(), SuiteEvent
.eventProperties(node
));
390 // TODO move it to an internal package?
391 static String
nodeToState(Node node
) {
392 return '/' + Jcr
.getWorkspaceName(node
) + Jcr
.getPath(node
);
395 private Node
stateToNode(SuiteUi suiteUi
, String state
) {
398 if (state
== null || !state
.startsWith("/"))
401 String path
= state
.substring(1);
403 if (path
.equals("")) {
407 int index
= path
.indexOf('/');
409 log
.error("Cannot interpret " + state
);
410 // cmsView.navigateTo("~");
412 } else if (index
> 0) {
413 workspace
= path
.substring(0, index
);
414 path
= path
.substring(index
);
415 } else {// index<0, assuming root node
420 Session session
= suiteUi
.getSession(workspace
);
423 Node node
= Jcr
.getNode(session
, path
);
432 public void handleEvent(Event event
) {
434 // Specific UI related events
435 SuiteUi ui
= getRelatedUi(event
);
439 String appTitle
= "";
440 if (ui
.getTitle() != null)
441 appTitle
= ui
.getTitle().lead() + " - ";
443 // String currentLayerId = ui.getCurrentLayerId();
444 // SuiteLayer currentLayer = currentLayerId != null ? layersByPid.get(currentLayerId).get() : null;
445 if (SuiteUiUtils
.isTopic(event
, SuiteEvent
.refreshPart
)) {
446 Node node
= getNode(ui
, event
);
449 CmsUiProvider uiProvider
= findByType(uiProvidersByType
, node
);
450 SuiteLayer layer
= findByType(layersByType
, node
);
451 ui
.switchToLayer(layer
, node
);
452 ui
.getCmsView().runAs(() -> layer
.view(uiProvider
, ui
.getCurrentWorkArea(), node
));
453 ui
.getCmsView().stateChanged(nodeToState(node
), appTitle
+ Jcr
.getTitle(node
));
454 } else if (SuiteUiUtils
.isTopic(event
, SuiteEvent
.openNewPart
)) {
455 Node node
= getNode(ui
, event
);
458 CmsUiProvider uiProvider
= findByType(uiProvidersByType
, node
);
459 SuiteLayer layer
= findByType(layersByType
, node
);
460 ui
.switchToLayer(layer
, node
);
461 ui
.getCmsView().runAs(() -> layer
.open(uiProvider
, ui
.getCurrentWorkArea(), node
));
462 ui
.getCmsView().stateChanged(nodeToState(node
), appTitle
+ Jcr
.getTitle(node
));
463 } else if (SuiteUiUtils
.isTopic(event
, SuiteEvent
.switchLayer
)) {
464 String layerId
= get(event
, SuiteEvent
.LAYER
);
465 if (layerId
!= null) {
466 // ui.switchToLayer(layerId, ui.getUserDir());
467 SuiteLayer suiteLayer
= findLayer(layerId
);
468 if (suiteLayer
== null)
469 throw new IllegalArgumentException("No layer '" + layerId
+ "' available.");
470 Localized layerTitle
= suiteLayer
.getTitle();
471 // FIXME make sure we don't rebuild the work area twice
472 Composite workArea
= ui
.getCmsView().doAs(() -> ui
.switchToLayer(layerId
, ui
.getUserDir()));
474 if (layerTitle
!= null)
475 title
= layerTitle
.lead();
476 Node nodeFromState
= getNode(ui
, event
);
477 if (nodeFromState
!= null && nodeFromState
.getPath().equals(ui
.getUserDir().getPath())) {
478 // default layer view is forced
479 String state
= defaultLayerPid
.equals(layerId
) ?
"~" : layerId
;
480 ui
.getCmsView().stateChanged(state
, appTitle
+ title
);
481 suiteLayer
.view(null, workArea
, nodeFromState
);
483 Node layerCurrentContext
= suiteLayer
.getCurrentContext(workArea
);
484 if (layerCurrentContext
!= null) {
485 // layer was already showing a context so we set the state to it
486 ui
.getCmsView().stateChanged(nodeToState(layerCurrentContext
),
487 appTitle
+ Jcr
.getTitle(layerCurrentContext
));
489 // no context was shown
490 ui
.getCmsView().stateChanged(layerId
, appTitle
+ title
);
494 Node node
= getNode(ui
, event
);
496 SuiteLayer layer
= findByType(layersByType
, node
);
497 ui
.getCmsView().runAs(() -> ui
.switchToLayer(layer
, node
));
501 } catch (Exception e
) {
502 log
.error("Cannot handle event " + event
, e
);
503 // CmsView.getCmsView(ui).exception(e);
508 private Node
getNode(SuiteUi ui
, Event event
) {
509 String nodePath
= get(event
, SuiteEvent
.NODE_PATH
);
510 if (nodePath
!= null && nodePath
.equals(HOME_STATE
))
511 return ui
.getUserDir();
512 String workspaceName
= get(event
, SuiteEvent
.WORKSPACE
);
513 Session session
= ui
.getSession(workspaceName
);
515 if (nodePath
== null) {
517 String username
= get(event
, SuiteEvent
.USERNAME
);
518 if (username
== null)
520 User user
= cmsUserManager
.getUser(username
);
525 userDn
= new LdapName(user
.getName());
526 } catch (InvalidNameException e
) {
527 throw new IllegalArgumentException("Badly formatted username", e
);
529 String userNodePath
= SuiteUtils
.getUserNodePath(userDn
);
530 if (Jcr
.itemExists(session
, userNodePath
))
531 node
= Jcr
.getNode(session
, userNodePath
);
533 Session adminSession
= null;
535 adminSession
= CmsJcrUtils
.openDataAdminSession(getRepository(), workspaceName
);
536 SuiteUtils
.getOrCreateUserNode(adminSession
, userDn
);
538 Jcr
.logout(adminSession
);
540 node
= Jcr
.getNode(session
, userNodePath
);
543 node
= Jcr
.getNode(session
, nodePath
);
548 private SuiteUi
getRelatedUi(Event event
) {
549 return managedUis
.get(get(event
, CMS_VIEW_UID_PROPERTY
));
552 public static String
get(Event event
, String key
) {
553 Object value
= event
.getProperty(key
);
556 // throw new IllegalArgumentException("Property " + key + " must be set");
557 return value
.toString();
562 * Dependency injection.
565 public void addUiProvider(CmsUiProvider uiProvider
, Map
<String
, Object
> properties
) {
566 if (properties
.containsKey(Constants
.SERVICE_PID
)) {
567 String pid
= (String
) properties
.get(Constants
.SERVICE_PID
);
568 RankedObject
.putIfHigherRank(uiProvidersByPid
, pid
, uiProvider
, properties
);
570 if (properties
.containsKey(EntityConstants
.TYPE
)) {
571 List
<String
> types
= LangUtils
.toStringList(properties
.get(EntityConstants
.TYPE
));
572 for (String type
: types
)
573 RankedObject
.putIfHigherRank(uiProvidersByType
, type
, uiProvider
, properties
);
577 public void removeUiProvider(CmsUiProvider uiProvider
, Map
<String
, Object
> properties
) {
578 if (properties
.containsKey(Constants
.SERVICE_PID
)) {
579 String pid
= (String
) properties
.get(Constants
.SERVICE_PID
);
580 if (uiProvidersByPid
.containsKey(pid
)) {
581 if (uiProvidersByPid
.get(pid
).equals(new RankedObject
<CmsUiProvider
>(uiProvider
, properties
))) {
582 uiProvidersByPid
.remove(pid
);
586 if (properties
.containsKey(EntityConstants
.TYPE
)) {
587 List
<String
> types
= LangUtils
.toStringList(properties
.get(EntityConstants
.TYPE
));
588 for (String type
: types
) {
589 if (uiProvidersByType
.containsKey(type
)) {
590 if (uiProvidersByType
.get(type
).equals(new RankedObject
<CmsUiProvider
>(uiProvider
, properties
))) {
591 uiProvidersByType
.remove(type
);
598 public void addLayer(SuiteLayer layer
, Map
<String
, Object
> properties
) {
599 if (properties
.containsKey(Constants
.SERVICE_PID
)) {
600 String pid
= (String
) properties
.get(Constants
.SERVICE_PID
);
601 RankedObject
.putIfHigherRank(layersByPid
, pid
, layer
, properties
);
603 if (properties
.containsKey(EntityConstants
.TYPE
)) {
604 List
<String
> types
= LangUtils
.toStringList(properties
.get(EntityConstants
.TYPE
));
605 for (String type
: types
)
606 RankedObject
.putIfHigherRank(layersByType
, type
, layer
, properties
);
610 public void removeLayer(SuiteLayer layer
, Map
<String
, Object
> properties
) {
611 if (properties
.containsKey(Constants
.SERVICE_PID
)) {
612 String pid
= (String
) properties
.get(Constants
.SERVICE_PID
);
613 if (layersByPid
.containsKey(pid
)) {
614 if (layersByPid
.get(pid
).equals(new RankedObject
<SuiteLayer
>(layer
, properties
))) {
615 layersByPid
.remove(pid
);
619 if (properties
.containsKey(EntityConstants
.TYPE
)) {
620 List
<String
> types
= LangUtils
.toStringList(properties
.get(EntityConstants
.TYPE
));
621 for (String type
: types
) {
622 if (layersByType
.containsKey(type
)) {
623 if (layersByType
.get(type
).equals(new RankedObject
<CmsUiProvider
>(layer
, properties
))) {
624 layersByType
.remove(type
);
631 public void setCmsUserManager(CmsUserManager cmsUserManager
) {
632 this.cmsUserManager
= cmsUserManager
;
635 public Repository
getRepository() {
639 public void setRepository(Repository repository
) {
640 this.repository
= repository
;