1 package org
.argeo
.cms
.web
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
6 import java
.util
.ArrayList
;
7 import java
.util
.Arrays
;
8 import java
.util
.Enumeration
;
9 import java
.util
.HashMap
;
10 import java
.util
.HashSet
;
11 import java
.util
.Hashtable
;
12 import java
.util
.LinkedHashMap
;
13 import java
.util
.List
;
17 import javax
.jcr
.Repository
;
18 import javax
.jcr
.RepositoryException
;
19 import javax
.jcr
.Session
;
20 import javax
.jcr
.security
.Privilege
;
21 import javax
.jcr
.version
.VersionManager
;
23 import org
.argeo
.api
.cms
.CmsConstants
;
24 import org
.argeo
.api
.cms
.CmsLog
;
25 import org
.argeo
.cms
.CmsException
;
26 import org
.argeo
.cms
.jcr
.CmsJcrUtils
;
27 import org
.argeo
.cms
.ui
.CmsUiConstants
;
28 import org
.argeo
.cms
.ui
.CmsUiProvider
;
29 import org
.argeo
.cms
.ui
.LifeCycleUiProvider
;
30 import org
.argeo
.cms
.ui
.util
.CmsUiUtils
;
31 import org
.argeo
.cms
.ui
.util
.StyleSheetResourceLoader
;
32 import org
.argeo
.jcr
.JcrUtils
;
33 import org
.eclipse
.rap
.rwt
.RWT
;
34 import org
.eclipse
.rap
.rwt
.application
.Application
;
35 import org
.eclipse
.rap
.rwt
.application
.Application
.OperationMode
;
36 import org
.eclipse
.rap
.rwt
.application
.ApplicationConfiguration
;
37 import org
.eclipse
.rap
.rwt
.application
.EntryPoint
;
38 import org
.eclipse
.rap
.rwt
.application
.EntryPointFactory
;
39 import org
.eclipse
.rap
.rwt
.application
.ExceptionHandler
;
40 import org
.eclipse
.rap
.rwt
.client
.WebClient
;
41 import org
.eclipse
.rap
.rwt
.client
.service
.JavaScriptExecutor
;
42 import org
.eclipse
.rap
.rwt
.service
.ResourceLoader
;
43 import org
.eclipse
.swt
.SWT
;
44 import org
.eclipse
.swt
.events
.SelectionAdapter
;
45 import org
.eclipse
.swt
.events
.SelectionEvent
;
46 import org
.eclipse
.swt
.layout
.FillLayout
;
47 import org
.eclipse
.swt
.widgets
.Button
;
48 import org
.eclipse
.swt
.widgets
.Composite
;
49 import org
.osgi
.framework
.Bundle
;
50 import org
.osgi
.framework
.BundleContext
;
51 import org
.osgi
.framework
.ServiceRegistration
;
53 /** A basic generic app based on {@link SimpleErgonomics}. */
55 public class SimpleApp
implements CmsUiConstants
, ApplicationConfiguration
{
56 private final static CmsLog log
= CmsLog
.getLog(SimpleApp
.class);
58 private String contextName
= null;
60 private Map
<String
, Map
<String
, String
>> branding
= new HashMap
<String
, Map
<String
, String
>>();
61 private Map
<String
, List
<String
>> styleSheets
= new HashMap
<String
, List
<String
>>();
63 private List
<String
> resources
= new ArrayList
<String
>();
65 private BundleContext bundleContext
;
67 private Repository repository
;
68 private String workspace
= null;
69 private String jcrBasePath
= "/";
70 private List
<String
> roPrincipals
= Arrays
.asList(CmsConstants
.ROLE_ANONYMOUS
, CmsConstants
.ROLE_USER
);
71 private List
<String
> rwPrincipals
= Arrays
.asList(CmsConstants
.ROLE_USER
);
73 private CmsUiProvider header
;
74 private Map
<String
, CmsUiProvider
> pages
= new LinkedHashMap
<String
, CmsUiProvider
>();
76 private Integer headerHeight
= 40;
78 private ServiceRegistration
<ApplicationConfiguration
> appReg
;
80 public void configure(Application application
) {
82 BundleResourceLoader bundleRL
= new BundleResourceLoader(bundleContext
.getBundle());
84 application
.setOperationMode(OperationMode
.SWT_COMPATIBILITY
);
85 // application.setOperationMode(OperationMode.JEE_COMPATIBILITY);
87 application
.setExceptionHandler(new CmsExceptionHandler());
89 // loading animated gif
90 application
.addResource(LOADING_IMAGE
, createResourceLoader(LOADING_IMAGE
));
92 application
.addResource(NO_IMAGE
, createResourceLoader(NO_IMAGE
));
94 for (String resource
: resources
) {
95 application
.addResource(resource
, bundleRL
);
96 if (log
.isTraceEnabled())
97 log
.trace("Resource " + resource
);
100 Map
<String
, String
> defaultBranding
= null;
101 if (branding
.containsKey("*"))
102 defaultBranding
= branding
.get("*");
103 // String defaultTheme = defaultBranding.get(WebClient.THEME_ID);
106 for (String page
: pages
.keySet()) {
107 Map
<String
, String
> properties
= defaultBranding
!= null ?
new HashMap
<String
, String
>(defaultBranding
)
108 : new HashMap
<String
, String
>();
109 if (branding
.containsKey(page
)) {
110 properties
.putAll(branding
.get(page
));
113 if (properties
.containsKey(WebClient
.FAVICON
)) {
114 String themeId
= defaultBranding
.get(WebClient
.THEME_ID
);
115 Bundle themeBundle
= findThemeBundle(bundleContext
, themeId
);
116 String faviconRelPath
= properties
.get(WebClient
.FAVICON
);
117 application
.addResource(faviconRelPath
,
118 new BundleResourceLoader(themeBundle
!= null ? themeBundle
: bundleContext
.getBundle()));
119 if (log
.isTraceEnabled())
120 log
.trace("Favicon " + faviconRelPath
);
125 if (!properties
.containsKey(WebClient
.PAGE_TITLE
)) {
126 if (page
.length() > 0)
127 properties
.put(WebClient
.PAGE_TITLE
, Character
.toUpperCase(page
.charAt(0)) + page
.substring(1));
131 if (!properties
.containsKey(WebClient
.BODY_HTML
))
132 properties
.put(WebClient
.BODY_HTML
, DEFAULT_LOADING_BODY
);
137 application
.addEntryPoint("/" + page
,
138 new CmsEntryPointFactory(pages
.get(page
), repository
, workspace
, properties
), properties
);
139 log
.info("Page /" + page
);
142 // stylesheets and themes
143 Set
<Bundle
> themeBundles
= new HashSet
<>();
144 for (String themeId
: styleSheets
.keySet()) {
145 Bundle themeBundle
= findThemeBundle(bundleContext
, themeId
);
146 StyleSheetResourceLoader styleSheetRL
= new StyleSheetResourceLoader(
147 themeBundle
!= null ? themeBundle
: bundleContext
.getBundle());
148 if (themeBundle
!= null)
149 themeBundles
.add(themeBundle
);
150 List
<String
> cssLst
= styleSheets
.get(themeId
);
151 if (log
.isDebugEnabled())
152 log
.debug("Theme " + themeId
);
153 for (String css
: cssLst
) {
154 application
.addStyleSheet(themeId
, css
, styleSheetRL
);
155 if (log
.isDebugEnabled())
156 log
.debug(" CSS " + css
);
160 for (Bundle themeBundle
: themeBundles
) {
161 BundleResourceLoader themeBRL
= new BundleResourceLoader(themeBundle
);
162 SimpleApp
.addThemeResources(application
, themeBundle
, themeBRL
, "*.png");
163 SimpleApp
.addThemeResources(application
, themeBundle
, themeBRL
, "*.gif");
164 SimpleApp
.addThemeResources(application
, themeBundle
, themeBRL
, "*.jpg");
166 } catch (RuntimeException e
) {
167 // Easier access to initialisation errors
168 log
.error("Unexpected exception when configuring RWT application.", e
);
173 public void init() throws RepositoryException
{
174 Session session
= null;
176 session
= CmsJcrUtils
.openDataAdminSession(repository
, workspace
);
177 // session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
178 VersionManager vm
= session
.getWorkspace().getVersionManager();
179 JcrUtils
.mkdirs(session
, jcrBasePath
);
181 if (!vm
.isCheckedOut(jcrBasePath
))
182 vm
.checkout(jcrBasePath
);
183 for (String principal
: rwPrincipals
)
184 JcrUtils
.addPrivilege(session
, jcrBasePath
, principal
, Privilege
.JCR_WRITE
);
185 for (String principal
: roPrincipals
)
186 JcrUtils
.addPrivilege(session
, jcrBasePath
, principal
, Privilege
.JCR_READ
);
188 for (String pageName
: pages
.keySet()) {
190 initPage(session
, pages
.get(pageName
));
192 } catch (Exception e
) {
193 throw new CmsException("Cannot initialize page " + pageName
, e
);
198 JcrUtils
.logoutQuietly(session
);
205 protected void initPage(Session adminSession
, CmsUiProvider page
) throws RepositoryException
{
206 if (page
instanceof LifeCycleUiProvider
)
207 ((LifeCycleUiProvider
) page
).init(adminSession
);
210 public void destroy() {
211 for (String pageName
: pages
.keySet()) {
213 CmsUiProvider page
= pages
.get(pageName
);
214 if (page
instanceof LifeCycleUiProvider
)
215 ((LifeCycleUiProvider
) page
).destroy();
216 } catch (Exception e
) {
217 log
.error("Cannot destroy page " + pageName
, e
);
222 protected void register() {
223 Hashtable
<String
, String
> props
= new Hashtable
<String
, String
>();
224 if (contextName
!= null)
225 props
.put("contextName", contextName
);
226 appReg
= bundleContext
.registerService(ApplicationConfiguration
.class, this, props
);
227 if (log
.isDebugEnabled())
228 log
.debug("Registered " + (contextName
== null ?
"/" : contextName
));
231 protected void unregister() {
233 if (log
.isDebugEnabled())
234 log
.debug("Unregistered " + (contextName
== null ?
"/" : contextName
));
237 public void setRepository(Repository repository
) {
238 this.repository
= repository
;
241 public void setWorkspace(String workspace
) {
242 this.workspace
= workspace
;
245 public void setHeader(CmsUiProvider header
) {
246 this.header
= header
;
249 public void setPages(Map
<String
, CmsUiProvider
> pages
) {
253 public void setJcrBasePath(String basePath
) {
254 this.jcrBasePath
= basePath
;
257 public void setRoPrincipals(List
<String
> roPrincipals
) {
258 this.roPrincipals
= roPrincipals
;
261 public void setRwPrincipals(List
<String
> rwPrincipals
) {
262 this.rwPrincipals
= rwPrincipals
;
265 public void setHeaderHeight(Integer headerHeight
) {
266 this.headerHeight
= headerHeight
;
269 public void setBranding(Map
<String
, Map
<String
, String
>> branding
) {
270 this.branding
= branding
;
273 public void setStyleSheets(Map
<String
, List
<String
>> styleSheets
) {
274 this.styleSheets
= styleSheets
;
277 public void setBundleContext(BundleContext bundleContext
) {
278 this.bundleContext
= bundleContext
;
281 public void setResources(List
<String
> resources
) {
282 this.resources
= resources
;
285 public void setContextName(String contextName
) {
286 this.contextName
= contextName
;
289 private static void addThemeResources(Application application
, Bundle themeBundle
, BundleResourceLoader themeBRL
,
291 Enumeration
<URL
> themeResources
= themeBundle
.findEntries("/", pattern
, true);
292 if (themeResources
== null)
294 while (themeResources
.hasMoreElements()) {
295 String resource
= themeResources
.nextElement().getPath();
296 // remove first '/' so that RWT registers it
297 resource
= resource
.substring(1);
298 if (!resource
.endsWith("/")) {
299 application
.addResource(resource
, themeBRL
);
300 if (log
.isTraceEnabled())
301 log
.trace("Registered " + resource
+ " from theme " + themeBundle
);
308 private static Bundle
findThemeBundle(BundleContext bundleContext
, String themeId
) {
312 // TODO deal with multiple versions
313 Bundle themeBundle
= null;
314 if (themeId
!= null) {
315 for (Bundle bundle
: bundleContext
.getBundles())
316 if (themeId
.equals(bundle
.getSymbolicName())) {
317 themeBundle
= bundle
;
324 class CmsExceptionHandler
implements ExceptionHandler
{
327 public void handleException(Throwable throwable
) {
329 CmsUiUtils
.getCmsView().exception(throwable
);
334 private class CmsEntryPointFactory
implements EntryPointFactory
{
335 private final CmsUiProvider page
;
336 private final Repository repository
;
337 private final String workspace
;
338 private final Map
<String
, String
> properties
;
340 public CmsEntryPointFactory(CmsUiProvider page
, Repository repository
, String workspace
,
341 Map
<String
, String
> properties
) {
343 this.repository
= repository
;
344 this.workspace
= workspace
;
345 this.properties
= properties
;
349 public EntryPoint
create() {
350 SimpleErgonomics entryPoint
= new SimpleErgonomics(repository
, workspace
, jcrBasePath
, page
, properties
) {
351 private static final long serialVersionUID
= -637940404865527290L;
354 protected void createAdminArea(Composite parent
) {
355 Composite adminArea
= new Composite(parent
, SWT
.NONE
);
356 adminArea
.setLayout(new FillLayout());
357 Button refresh
= new Button(adminArea
, SWT
.PUSH
);
358 refresh
.setText("Reload App");
359 refresh
.addSelectionListener(new SelectionAdapter() {
360 private static final long serialVersionUID
= -7671999525536351366L;
363 public void widgetSelected(SelectionEvent e
) {
364 long timeBeforeReload
= 1000;
365 RWT
.getClient().getService(JavaScriptExecutor
.class).execute(
366 "setTimeout(function() { " + "location.reload();" + "}," + timeBeforeReload
+ ");");
372 // entryPoint.setState("");
373 entryPoint
.setHeader(header
);
374 entryPoint
.setHeaderHeight(headerHeight
);
375 // CmsSession.current.set(entryPoint);
379 private void reloadApp() {
380 new Thread("Refresh app") {
390 private static ResourceLoader
createResourceLoader(final String resourceName
) {
391 return new ResourceLoader() {
392 public InputStream
getResourceAsStream(String resourceName
) throws IOException
{
393 return getClass().getClassLoader().getResourceAsStream(resourceName
);
398 // private static ResourceLoader createUrlResourceLoader(final URL url) {
399 // return new ResourceLoader() {
400 // public InputStream getResourceAsStream(String resourceName)
401 // throws IOException {
402 // return url.openStream();
410 private static String DEFAULT_LOADING_BODY
= "<div"
411 + " style=\"position: absolute; left: 50%; top: 50%; margin: -32px -32px; width: 64px; height:64px\">"
412 + "<img src=\"./rwt-resources/" + LOADING_IMAGE
413 + "\" width=\"32\" height=\"32\" style=\"margin: 16px 16px\"/>" + "</div>";