1 package org
.argeo
.app
.swt
.ux
;
3 import static org
.argeo
.api
.cms
.ux
.CmsView
.CMS_VIEW_UID_PROPERTY
;
5 import java
.lang
.ref
.WeakReference
;
6 import java
.util
.ArrayList
;
7 import java
.util
.Collections
;
8 import java
.util
.HashMap
;
9 import java
.util
.HashSet
;
10 import java
.util
.Iterator
;
11 import java
.util
.List
;
12 import java
.util
.Locale
;
14 import java
.util
.Objects
;
16 import java
.util
.Timer
;
17 import java
.util
.TimerTask
;
18 import java
.util
.TreeMap
;
20 import javax
.xml
.namespace
.QName
;
22 import org
.argeo
.api
.acr
.Content
;
23 import org
.argeo
.api
.acr
.ContentRepository
;
24 import org
.argeo
.api
.acr
.spi
.ProvidedSession
;
25 import org
.argeo
.api
.app
.AppUserState
;
26 import org
.argeo
.api
.app
.EntityConstants
;
27 import org
.argeo
.api
.app
.EntityName
;
28 import org
.argeo
.api
.app
.EntityType
;
29 import org
.argeo
.api
.app
.RankedObject
;
30 import org
.argeo
.api
.cms
.CmsConstants
;
31 import org
.argeo
.api
.cms
.CmsEvent
;
32 import org
.argeo
.api
.cms
.CmsEventSubscriber
;
33 import org
.argeo
.api
.cms
.CmsLog
;
34 import org
.argeo
.api
.cms
.CmsSession
;
35 import org
.argeo
.api
.cms
.ux
.CmsTheme
;
36 import org
.argeo
.api
.cms
.ux
.CmsUi
;
37 import org
.argeo
.api
.cms
.ux
.CmsView
;
38 import org
.argeo
.app
.ux
.AbstractArgeoApp
;
39 import org
.argeo
.app
.ux
.AppUi
;
40 import org
.argeo
.app
.ux
.SuiteUxEvent
;
41 import org
.argeo
.cms
.LocaleUtils
;
42 import org
.argeo
.cms
.Localized
;
43 import org
.argeo
.cms
.swt
.CmsSwtUtils
;
44 import org
.argeo
.cms
.swt
.acr
.SwtUiProvider
;
45 import org
.argeo
.cms
.swt
.dialogs
.CmsFeedback
;
46 import org
.argeo
.cms
.util
.LangUtils
;
47 import org
.argeo
.cms
.ux
.CmsUxUtils
;
48 import org
.argeo
.eclipse
.ui
.specific
.UiContext
;
49 import org
.eclipse
.swt
.SWT
;
50 import org
.eclipse
.swt
.events
.DisposeEvent
;
51 import org
.eclipse
.swt
.events
.DisposeListener
;
52 import org
.eclipse
.swt
.widgets
.Composite
;
53 import org
.osgi
.framework
.Constants
;
55 /** The Argeo Suite App. */
56 public class SwtArgeoApp
extends AbstractArgeoApp
implements CmsEventSubscriber
{
57 private final static CmsLog log
= CmsLog
.getLog(SwtArgeoApp
.class);
59 public final static String PUBLIC_BASE_PATH_PROPERTY
= "publicBasePath";
60 public final static String DEFAULT_UI_NAME_PROPERTY
= "defaultUiName";
61 public final static String DEFAULT_THEME_ID_PROPERTY
= "defaultThemeId";
62 public final static String DEFAULT_LAYER_PROPERTY
= "defaultLayer";
63 public final static String SHARED_PID_PREFIX_PROPERTY
= "sharedPidPrefix";
65 private final static String LOGIN
= "login";
66 private final static String HOME_STATE
= "~";
68 private String publicBasePath
= null;
70 private String appPid
;
71 private String pidPrefix
;
72 private String sharedPidPrefix
;
74 // private String headerPid;
75 // private String footerPid;
76 // private String leadPanePid;
77 // private String adminLeadPanePid;
78 // private String loginScreenPid;
80 private String defaultUiName
= "app";
81 private String adminUiName
= "admin";
83 // FIXME such default names make refactoring more dangerous
85 private String defaultLayerPid
= "argeo.suite.ui.dashboardLayer";
87 private String defaultThemeId
= "org.argeo.app.theme.default";
89 // TODO use QName as key for byType
90 private Map
<String
, RankedObject
<SwtUiProvider
>> uiProvidersByPid
= Collections
.synchronizedMap(new HashMap
<>());
91 private Map
<String
, RankedObject
<SwtUiProvider
>> uiProvidersByType
= Collections
.synchronizedMap(new HashMap
<>());
92 private Map
<String
, RankedObject
<SwtAppLayer
>> layersByPid
= Collections
.synchronizedSortedMap(new TreeMap
<>());
93 private Map
<String
, RankedObject
<SwtAppLayer
>> layersByType
= Collections
.synchronizedSortedMap(new TreeMap
<>());
95 // private CmsUserManager cmsUserManager;
97 // TODO make more optimal or via CmsSession/CmsView
98 private static Timer janitorTimer
= new Timer(true);
99 private Map
<String
, WeakReference
<SwtAppUi
>> managedUis
= new HashMap
<>();
102 private ContentRepository contentRepository
;
103 private AppUserState appUserState
;
105 // private Repository repository;
107 public void start(Map
<String
, Object
> properties
) {
108 for (SuiteUxEvent event
: SuiteUxEvent
.values()) {
109 getCmsContext().getCmsEventBus().addEventSubscriber(event
.topic(), this);
112 if (properties
.containsKey(DEFAULT_UI_NAME_PROPERTY
))
113 defaultUiName
= LangUtils
.get(properties
, DEFAULT_UI_NAME_PROPERTY
);
114 if (properties
.containsKey(DEFAULT_THEME_ID_PROPERTY
))
115 defaultThemeId
= LangUtils
.get(properties
, DEFAULT_THEME_ID_PROPERTY
);
116 if (properties
.containsKey(DEFAULT_LAYER_PROPERTY
))
117 defaultLayerPid
= LangUtils
.get(properties
, DEFAULT_LAYER_PROPERTY
);
118 sharedPidPrefix
= LangUtils
.get(properties
, SHARED_PID_PREFIX_PROPERTY
);
119 publicBasePath
= LangUtils
.get(properties
, PUBLIC_BASE_PATH_PROPERTY
);
121 if (properties
.containsKey(Constants
.SERVICE_PID
)) {
122 appPid
= properties
.get(Constants
.SERVICE_PID
).toString();
123 int lastDotIndex
= appPid
.lastIndexOf('.');
124 if (lastDotIndex
>= 0) {
125 pidPrefix
= appPid
.substring(0, lastDotIndex
);
128 // TODO does it make sense to accept that?
129 appPid
= "<unknown>";
131 Objects
.requireNonNull(contentRepository
, "Content repository must be provided");
132 Objects
.requireNonNull(appUserState
, "App user state must be provided");
134 long janitorPeriod
= 60 * 60 * 1000;// 1h
135 // long janitorPeriod = 60 * 1000;// min
136 janitorTimer
.schedule(new TimerTask() {
141 // copy Map in order to avoid concurrent modification exception
142 Iterator
<Map
.Entry
<String
, WeakReference
<SwtAppUi
>>> uiRefs
= new HashMap
<>(managedUis
).entrySet()
144 refs
: while (uiRefs
.hasNext()) {
145 Map
.Entry
<String
, WeakReference
<SwtAppUi
>> entry
= uiRefs
.next();
146 String uiUuid
= entry
.getKey();
147 WeakReference
<SwtAppUi
> uiRef
= entry
.getValue();
148 SwtAppUi ui
= uiRef
.get();
150 if (log
.isTraceEnabled())
151 log
.warn("Unreferenced UI " + uiUuid
+ " in " + appPid
+ ", removing it");
152 managedUis
.remove(uiUuid
);
155 if (!ui
.isDisposed() && !ui
.getDisplay().isDisposed()) {
156 if (ui
.isTimedOut()) {
157 if (log
.isTraceEnabled())
158 log
.trace("Killing timed-out UI " + uiUuid
+ " in " + appPid
);
159 UiContext
.killDisplay(ui
.getDisplay());
162 if (log
.isTraceEnabled())
163 log
.warn("Disposed UI " + uiUuid
+ " still referenced in " + appPid
+ ", removing it");
164 managedUis
.remove(uiUuid
);
167 if (log
.isTraceEnabled())
168 log
.trace(managedUis
.size() + " UIs being managed by app " + appPid
);
169 } catch (Exception e
) {
170 log
.error("Could not clean up timed-out UIs", e
);
173 }, janitorPeriod
, janitorPeriod
);
175 if (log
.isDebugEnabled())
176 log
.info("Argeo Suite App " + appPid
+ " started");
179 public void stop(Map
<String
, Object
> properties
) {
180 refs
: for (WeakReference
<SwtAppUi
> uiRef
: managedUis
.values()) {
181 SwtAppUi ui
= uiRef
.get();
184 if (!ui
.isDisposed() && !ui
.getDisplay().isDisposed()) {
185 ui
.getDisplay().syncExec(() -> ui
.dispose());
189 if (log
.isDebugEnabled())
190 log
.info("Argeo Suite App stopped");
195 public Set
<String
> getUiNames() {
196 HashSet
<String
> uiNames
= new HashSet
<>();
197 uiNames
.add(defaultUiName
);
198 uiNames
.add(adminUiName
);
203 public CmsUi
initUi(Object parent
) {
204 Composite uiParent
= (Composite
) parent
;
205 String uiName
= uiParent
.getData(UI_NAME_PROPERTY
) != null ? uiParent
.getData(UI_NAME_PROPERTY
).toString()
207 CmsView cmsView
= CmsSwtUtils
.getCmsView(uiParent
);
209 throw new IllegalStateException("No CMS view is registered.");
210 CmsTheme theme
= getTheme(uiName
);
212 CmsSwtUtils
.registerCmsTheme(uiParent
.getShell(), theme
);
213 SwtAppUi argeoSuiteUi
= new SwtAppUi(uiParent
, SWT
.INHERIT_DEFAULT
);
214 // TODO make timeout configurable
215 argeoSuiteUi
.setUiTimeout(6 * 60 * 60 * 1000);// 6 hours
216 // argeoSuiteUi.setUiTimeout(60 * 1000);// 1 min
217 String uid
= cmsView
.getUid();
218 argeoSuiteUi
.addDisposeListener(new CleanUpUi(uid
));
219 managedUis
.put(uid
, new WeakReference
<>(argeoSuiteUi
));
224 public String
getThemeId(String uiName
) {
225 String themeId
= System
.getProperty("org.argeo.app.theme.default");
228 return defaultThemeId
;
232 public void refreshUi(CmsUi cmsUi
, String state
) {
234 Content context
= null;
235 SwtAppUi ui
= (SwtAppUi
) cmsUi
;
236 ui
.updateLastAccess();
238 String uiName
= Objects
.toString(ui
.getParent().getData(UI_NAME_PROPERTY
), null);
240 throw new IllegalStateException("UI name should not be null");
241 CmsView cmsView
= CmsSwtUtils
.getCmsView(ui
);
243 ProvidedSession contentSession
= (ProvidedSession
) CmsUxUtils
.getContentSession(contentRepository
, cmsView
);
245 SwtUiProvider headerUiProvider
= findStructuralUiProvider(SwtAppUi
.Structural
.header
.name());
246 SwtUiProvider footerUiProvider
= findStructuralUiProvider(SwtAppUi
.Structural
.footer
.name());
247 SwtUiProvider leadPaneUiProvider
;
248 if (adminUiName
.equals(uiName
)) {
249 leadPaneUiProvider
= findStructuralUiProvider(SwtAppUi
.Structural
.adminLeadPane
.name());
251 leadPaneUiProvider
= findStructuralUiProvider(SwtAppUi
.Structural
.leadPane
.name());
254 Localized appTitle
= null;
255 if (headerUiProvider
instanceof DefaultHeader
) {
256 appTitle
= ((DefaultHeader
) headerUiProvider
).getTitle();
258 ui
.setTitle(appTitle
);
260 if (cmsView
.isAnonymous() && publicBasePath
== null) {// internal app, must login
262 ui
.setLoginScreen(true);
263 if (headerUiProvider
!= null)
264 refreshPart(headerUiProvider
, ui
.getHeader(), context
);
265 ui
.refreshBelowHeader(false);
266 SwtUiProvider loginScreenUiProvider
= findStructuralUiProvider(SwtAppUi
.Structural
.loginScreen
.name());
267 refreshPart(loginScreenUiProvider
, ui
.getBelowHeader(), context
);
268 if (footerUiProvider
!= null)
269 refreshPart(footerUiProvider
, ui
.getFooter(), context
);
270 ui
.layout(true, true);
273 if (LOGIN
.equals(state
))
275 if (ui
.isLoginScreen()) {
276 ui
.setLoginScreen(false);
278 CmsSession cmsSession
= cmsView
.getCmsSession();
279 if (ui
.getUserDir() == null) {
280 // FIXME NPE on CMSSession when logging in from anonymous
281 if (cmsSession
== null || cmsView
.isAnonymous()) {
282 assert publicBasePath
!= null;
283 Content userDir
= contentSession
284 .get(Content
.ROOT_PATH
+ CmsConstants
.SYS_WORKSPACE
+ publicBasePath
);
285 ui
.setUserDir(userDir
);
287 Content userDir
= appUserState
.getOrCreateSessionDir(cmsSession
);
288 ui
.setUserDir(userDir
);
289 // Node userDirNode = jcrContentProvider.doInAdminSession((adminSession) -> {
290 // Node node = SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession);
293 // Content userDir = contentSession
294 // .get(ContentUtils.SLASH + CmsConstants.SYS_WORKSPACE + userDirNode.getPath());
295 // ui.setUserDir(userDir);
298 initLocale(cmsSession
);
299 context
= stateToNode(ui
, state
);
301 context
= ui
.getUserDir();
303 if (headerUiProvider
!= null)
304 refreshPart(headerUiProvider
, ui
.getHeader(), context
);
305 ui
.refreshBelowHeader(true);
306 for (String key
: layersByPid
.keySet()) {
307 SwtAppLayer layer
= layersByPid
.get(key
).get();
308 ui
.addLayer(key
, layer
);
311 if (leadPaneUiProvider
!= null)
312 refreshPart(leadPaneUiProvider
, ui
.getLeadPane(), context
);
313 if (footerUiProvider
!= null)
314 refreshPart(footerUiProvider
, ui
.getFooter(), context
);
315 ui
.layout(true, true);
316 setState(ui
, state
!= null ? state
: defaultLayerPid
);
318 } catch (Exception e
) {
319 CmsFeedback
.error("Unexpected exception", e
);
323 private void initLocale(CmsSession cmsSession
) {
324 if (cmsSession
== null)
326 Locale locale
= cmsSession
.getLocale();
327 UiContext
.setLocale(locale
);
328 LocaleUtils
.setThreadLocale(locale
);
332 private void refreshPart(SwtUiProvider uiProvider
, Composite part
, Content context
) {
333 CmsSwtUtils
.clear(part
);
334 uiProvider
.createUiPart(part
, context
);
337 private SwtUiProvider
findStructuralUiProvider(String suffix
) {
338 SwtUiProvider res
= null;
339 if (pidPrefix
!= null)
340 res
= findUiProvider(pidPrefix
+ "." + suffix
);
343 if (sharedPidPrefix
!= null)
344 res
= findUiProvider(sharedPidPrefix
+ "." + suffix
);
348 private SwtUiProvider
findUiProvider(String pid
) {
349 if (!uiProvidersByPid
.containsKey(pid
))
351 return uiProvidersByPid
.get(pid
).get();
354 private SwtAppLayer
findLayer(String pid
) {
355 if (!layersByPid
.containsKey(pid
))
357 return layersByPid
.get(pid
).get();
360 private List
<String
> listTypes(Map
<String
, ?
extends Object
> byType
, Content content
) {
362 throw new IllegalArgumentException("A content should be provided");
363 List
<String
> types
= new ArrayList
<>();
364 if (content
.hasContentClass(EntityType
.entity
.qName())) {
365 String type
= content
.attr(EntityName
.type
.qName());
366 if (type
!= null && byType
.containsKey(type
))
370 List
<QName
> objectClasses
= content
.getContentClasses();
371 for (QName cc
: objectClasses
) {
372 String type
= cc
.getPrefix() + ":" + cc
.getLocalPart();
373 if (byType
.containsKey(type
))
377 throw new IllegalArgumentException("No type found for " + content
+ " (" + objectClasses
+ ")");
381 private RankedObject
<SwtAppLayer
> findLayerByType(Content content
) {
382 List
<String
> types
= listTypes(layersByType
, content
);
383 // we assume the types will be ordered by priority
384 // (no possible for LDAP at this stage)
385 for (String type
: types
) {
386 if (layersByType
.containsKey(type
))
387 return layersByType
.get(type
);
389 throw new IllegalArgumentException("No layer found for " + content
+ " with type " + types
);
392 private RankedObject
<SwtUiProvider
> findUiProviderByType(Content content
) {
393 RankedObject
<SwtAppLayer
> layerRO
= findLayerByType(content
);
394 List
<String
> layerTypes
= LangUtils
.toStringList(layerRO
.getProperties().get(EntityConstants
.TYPE
));
395 List
<String
> types
= listTypes(uiProvidersByType
, content
);
396 // layer types are ordered by priority
397 for (String type
: layerTypes
) {
398 if (types
.contains(type
) && uiProvidersByType
.containsKey(type
))
399 return uiProvidersByType
.get(type
);
401 throw new IllegalArgumentException("No UI provider found for " + content
+ " with types " + types
);
405 public void setState(CmsUi cmsUi
, String state
) {
406 AppUi ui
= (AppUi
) cmsUi
;
409 if (!state
.startsWith("/")) {
410 if (LOGIN
.equals(state
)) {
411 String appTitle
= "";
412 if (ui
.getTitle() != null)
413 appTitle
= ui
.getTitle().lead();
414 ui
.getCmsView().stateChanged(state
, appTitle
);
417 Map
<String
, Object
> properties
= new HashMap
<>();
418 String layerId
= HOME_STATE
.equals(state
) ? defaultLayerPid
: state
;
419 properties
.put(SuiteUxEvent
.LAYER
, layerId
);
420 properties
.put(SuiteUxEvent
.CONTENT_PATH
, HOME_STATE
);
421 ui
.getCmsView().sendEvent(SuiteUxEvent
.switchLayer
.topic(), properties
);
424 if (ui
.isLoginScreen()) {
428 Content node
= stateToNode(ui
, state
);
430 ui
.getCmsView().navigateTo(HOME_STATE
);
432 ui
.getCmsView().sendEvent(SuiteUxEvent
.switchLayer
.topic(), SuiteUxEvent
.eventProperties(node
));
433 ui
.getCmsView().sendEvent(SuiteUxEvent
.refreshPart
.topic(), SuiteUxEvent
.eventProperties(node
));
437 // TODO move it to an internal package?
438 private static String
nodeToState(Content node
) {
439 return node
.getPath();
442 private Content
stateToNode(CmsUi suiteUi
, String state
) {
445 if (state
== null || !state
.startsWith("/"))
450 ProvidedSession contentSession
= (ProvidedSession
) CmsUxUtils
.getContentSession(contentRepository
,
451 suiteUi
.getCmsView());
452 return contentSession
.get(path
);
460 public void onEvent(String topic
, Map
<String
, Object
> event
) {
462 // Specific UI related events
463 SwtAppUi ui
= getRelatedUi(event
);
466 ui
.updateLastAccess();
467 ui
.getCmsView().runAs(() -> {
469 String appTitle
= "";
470 if (ui
.getTitle() != null)
471 appTitle
= ui
.getTitle().lead();
473 if (isTopic(topic
, SuiteUxEvent
.refreshPart
)) {
474 Content content
= getContentFromEvent(ui
, event
);
477 SwtUiProvider uiProvider
= findUiProviderByType(content
).get();
478 SwtAppLayer layer
= findLayerByType(content
).get();
479 ui
.switchToLayer(layer
, content
);
480 layer
.view(uiProvider
, ui
.getCurrentWorkArea(), content
);
481 ui
.getCmsView().stateChanged(nodeToState(content
),
482 stateTitle(appTitle
, CmsUxUtils
.getTitle(content
)));
483 } else if (isTopic(topic
, SuiteUxEvent
.openNewPart
)) {
484 Content content
= getContentFromEvent(ui
, event
);
487 SwtUiProvider uiProvider
= findUiProviderByType(content
).get();
488 SwtAppLayer layer
= findLayerByType(content
).get();
489 ui
.switchToLayer(layer
, content
);
490 layer
.open(uiProvider
, ui
.getCurrentWorkArea(), content
);
491 ui
.getCmsView().stateChanged(nodeToState(content
),
492 stateTitle(appTitle
, CmsUxUtils
.getTitle(content
)));
493 } else if (isTopic(topic
, SuiteUxEvent
.switchLayer
)) {
494 String layerId
= get(event
, SuiteUxEvent
.LAYER
);
495 if (layerId
!= null && !"".equals(layerId
.trim())) {
496 SwtAppLayer suiteLayer
= findLayer(layerId
);
497 if (suiteLayer
== null)
498 throw new IllegalArgumentException("No layer '" + layerId
+ "' available.");
499 Localized layerTitle
= suiteLayer
.getTitle();
500 // FIXME make sure we don't rebuild the work area twice
501 Composite workArea
= ui
.switchToLayer(layerId
, ui
.getUserDir());
503 if (layerTitle
!= null)
504 title
= layerTitle
.lead();
505 Content nodeFromState
= getContentFromEvent(ui
, event
);
506 if (nodeFromState
!= null && nodeFromState
.getPath().equals(ui
.getUserDir().getPath())) {
507 // default layer view is forced
508 String state
= defaultLayerPid
.equals(layerId
) ?
"~" : layerId
;
509 ui
.getCmsView().stateChanged(state
, stateTitle(appTitle
, title
));
510 suiteLayer
.view(null, workArea
, nodeFromState
);
512 Content layerCurrentContext
= suiteLayer
.getCurrentContext(workArea
);
513 if (layerCurrentContext
!= null && !layerCurrentContext
.equals(ui
.getUserDir())) {
514 // layer was already showing a context so we set the state to it
515 ui
.getCmsView().stateChanged(nodeToState(layerCurrentContext
),
516 stateTitle(appTitle
, CmsUxUtils
.getTitle(layerCurrentContext
)));
518 // no context was shown
519 ui
.getCmsView().stateChanged(layerId
, stateTitle(appTitle
, title
));
523 Content content
= getContentFromEvent(ui
, event
);
524 if (content
!= null) {
525 SwtAppLayer layer
= findLayerByType(content
).get();
526 ui
.switchToLayer(layer
, content
);
530 } catch (Exception e
) {
531 CmsFeedback
.error("Cannot handle event " + topic
+ " " + event
, e
);
532 // log.error("Cannot handle event " + event, e);
537 private String
stateTitle(String appTitle
, String additionalTitle
) {
538 return additionalTitle
== null ? appTitle
: appTitle
+ " - " + additionalTitle
;
541 private boolean isTopic(String topic
, CmsEvent cmsEvent
) {
542 Objects
.requireNonNull(topic
);
543 return topic
.equals(cmsEvent
.topic());
546 protected Content
getContentFromEvent(SwtAppUi ui
, Map
<String
, Object
> event
) {
547 ProvidedSession contentSession
= (ProvidedSession
) CmsUxUtils
.getContentSession(contentRepository
,
550 String path
= get(event
, SuiteUxEvent
.CONTENT_PATH
);
552 if (path
!= null && (path
.equals(HOME_STATE
) || path
.equals("")))
553 return ui
.getUserDir();
558 node
= contentSession
.get(path
);
563 private SwtAppUi
getRelatedUi(Map
<String
, Object
> eventProperties
) {
564 WeakReference
<SwtAppUi
> uiRef
= managedUis
.get(get(eventProperties
, CMS_VIEW_UID_PROPERTY
));
570 public static String
get(Map
<String
, Object
> eventProperties
, String key
) {
571 Object value
= eventProperties
.get(key
);
574 return value
.toString();
579 * Dependency injection.
582 public void addUiProvider(SwtUiProvider uiProvider
, Map
<String
, Object
> properties
) {
583 if (properties
.containsKey(Constants
.SERVICE_PID
)) {
584 String pid
= (String
) properties
.get(Constants
.SERVICE_PID
);
585 RankedObject
.putIfHigherRank(uiProvidersByPid
, pid
, uiProvider
, properties
);
587 if (properties
.containsKey(EntityConstants
.TYPE
)) {
588 List
<String
> types
= LangUtils
.toStringList(properties
.get(EntityConstants
.TYPE
));
589 for (String type
: types
) {
590 RankedObject
.putIfHigherRank(uiProvidersByType
, type
, uiProvider
, properties
);
595 public void removeUiProvider(SwtUiProvider uiProvider
, Map
<String
, Object
> properties
) {
596 if (properties
.containsKey(Constants
.SERVICE_PID
)) {
597 String pid
= (String
) properties
.get(Constants
.SERVICE_PID
);
598 if (uiProvidersByPid
.containsKey(pid
)) {
599 if (uiProvidersByPid
.get(pid
).equals(new RankedObject
<SwtUiProvider
>(uiProvider
, properties
))) {
600 uiProvidersByPid
.remove(pid
);
604 if (properties
.containsKey(EntityConstants
.TYPE
)) {
605 List
<String
> types
= LangUtils
.toStringList(properties
.get(EntityConstants
.TYPE
));
606 for (String type
: types
) {
607 if (uiProvidersByType
.containsKey(type
)) {
608 if (uiProvidersByType
.get(type
).equals(new RankedObject
<SwtUiProvider
>(uiProvider
, properties
))) {
609 uiProvidersByType
.remove(type
);
616 public void addLayer(SwtAppLayer layer
, Map
<String
, Object
> properties
) {
617 if (properties
.containsKey(Constants
.SERVICE_PID
)) {
618 String pid
= (String
) properties
.get(Constants
.SERVICE_PID
);
619 RankedObject
.putIfHigherRank(layersByPid
, pid
, layer
, properties
);
621 if (properties
.containsKey(EntityConstants
.TYPE
)) {
622 // TODO check consistency of entity types with overridden ?
623 List
<String
> types
= LangUtils
.toStringList(properties
.get(EntityConstants
.TYPE
));
624 for (String type
: types
)
625 RankedObject
.putIfHigherRank(layersByType
, type
, layer
, properties
);
629 public void removeLayer(SwtAppLayer layer
, Map
<String
, Object
> properties
) {
630 if (properties
.containsKey(Constants
.SERVICE_PID
)) {
631 String pid
= (String
) properties
.get(Constants
.SERVICE_PID
);
632 if (layersByPid
.containsKey(pid
)) {
633 if (layersByPid
.get(pid
).equals(new RankedObject
<SwtAppLayer
>(layer
, properties
))) {
634 layersByPid
.remove(pid
);
638 if (properties
.containsKey(EntityConstants
.TYPE
)) {
639 List
<String
> types
= LangUtils
.toStringList(properties
.get(EntityConstants
.TYPE
));
640 for (String type
: types
) {
641 if (layersByType
.containsKey(type
)) {
642 if (layersByType
.get(type
).equals(new RankedObject
<SwtAppLayer
>(layer
, properties
))) {
643 layersByType
.remove(type
);
650 public void setContentRepository(ContentRepository contentRepository
) {
651 this.contentRepository
= contentRepository
;
654 public void setAppUserState(AppUserState appUserState
) {
655 this.appUserState
= appUserState
;
659 * Dedicated class to clean up the UI in order to avoid illegal access issues
662 private class CleanUpUi
implements DisposeListener
{
663 private static final long serialVersionUID
= 1905900302262082463L;
666 public CleanUpUi(String uid
) {
671 public void widgetDisposed(DisposeEvent e
) {
672 managedUis
.remove(uid
);
673 if (log
.isDebugEnabled())
674 log
.debug("App " + appPid
+ " - Suite UI " + uid
+ " has been disposed (" + managedUis
.size()
675 + " UIs still being managed).");