]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/CmsApplication.java
Clean up code
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / CmsApplication.java
1 package org.argeo.cms;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.PrintWriter;
6 import java.io.StringWriter;
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.HashMap;
10 import java.util.LinkedHashMap;
11 import java.util.List;
12 import java.util.Map;
13
14 import javax.jcr.Node;
15 import javax.jcr.Repository;
16 import javax.jcr.RepositoryException;
17 import javax.jcr.Session;
18 import javax.jcr.security.Privilege;
19 import javax.jcr.version.VersionManager;
20
21 import org.apache.commons.io.IOUtils;
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.argeo.cms.internal.ImageManagerImpl;
25 import org.argeo.cms.util.CmsUtils;
26 import org.argeo.jcr.JcrUtils;
27 import org.eclipse.gemini.blueprint.context.BundleContextAware;
28 import org.eclipse.rap.rwt.RWT;
29 import org.eclipse.rap.rwt.application.Application;
30 import org.eclipse.rap.rwt.application.Application.OperationMode;
31 import org.eclipse.rap.rwt.application.ApplicationConfiguration;
32 import org.eclipse.rap.rwt.application.EntryPoint;
33 import org.eclipse.rap.rwt.application.EntryPointFactory;
34 import org.eclipse.rap.rwt.application.ExceptionHandler;
35 import org.eclipse.rap.rwt.client.WebClient;
36 import org.eclipse.rap.rwt.service.ResourceLoader;
37 import org.eclipse.swt.SWT;
38 import org.eclipse.swt.layout.FillLayout;
39 import org.eclipse.swt.layout.GridData;
40 import org.eclipse.swt.widgets.Composite;
41 import org.eclipse.swt.widgets.Control;
42 import org.eclipse.swt.widgets.Label;
43 import org.eclipse.swt.widgets.Text;
44 import org.osgi.framework.BundleContext;
45
46 /** Configures an Argeo CMS RWT application. */
47 public class CmsApplication implements CmsConstants, ApplicationConfiguration,
48 BundleContextAware {
49 final static Log log = LogFactory.getLog(CmsApplication.class);
50
51 // private Map<String, EntryPointFactory> entryPoints = new HashMap<String,
52 // EntryPointFactory>();
53 private Map<String, Map<String, String>> branding = new HashMap<String, Map<String, String>>();
54 private Map<String, List<String>> styleSheets = new HashMap<String, List<String>>();
55
56 private List<String> resources = new ArrayList<String>();
57
58 // private Bundle clientScriptingBundle;
59 private BundleContext bundleContext;
60
61 private Repository repository;
62 private String workspace = null;
63 private String basePath = "/";
64 private List<String> roPrincipals = Arrays.asList("anonymous", "everyone");
65 private List<String> rwPrincipals = Arrays.asList("everyone");
66
67 private CmsLogin cmsLogin;
68
69 private CmsUiProvider header;
70 private Map<String, CmsUiProvider> pages = new LinkedHashMap<String, CmsUiProvider>();
71
72 private Integer headerHeight = 40;
73
74 // Managers
75 private CmsImageManager imageManager = new ImageManagerImpl();
76
77 public void configure(Application application) {
78 try {
79 application.setOperationMode(OperationMode.SWT_COMPATIBILITY);
80 application.setExceptionHandler(new CmsExceptionHandler());
81
82 // TODO load all pics under icons
83 // loading animated gif
84 application.addResource(LOADING_IMAGE,
85 createResourceLoader(LOADING_IMAGE));
86 // empty image
87 application.addResource(NO_IMAGE, createResourceLoader(NO_IMAGE));
88
89 for (String resource : resources) {
90 application.addResource(resource, new BundleResourceLoader(
91 bundleContext));
92 if (log.isDebugEnabled())
93 log.debug("Registered resource " + resource);
94 }
95
96 Map<String, String> defaultBranding = null;
97 if (branding.containsKey("*"))
98 defaultBranding = branding.get("*");
99
100 // entry points
101 for (String page : pages.keySet()) {
102 Map<String, String> properties = defaultBranding != null ? new HashMap<String, String>(
103 defaultBranding) : new HashMap<String, String>();
104 if (branding.containsKey(page)) {
105 properties.putAll(branding.get(page));
106 }
107 // favicon
108 if (properties.containsKey(WebClient.FAVICON)) {
109 String faviconRelPath = properties.get(WebClient.FAVICON);
110 application.addResource(faviconRelPath,
111 new BundleResourceLoader(bundleContext));
112 if (log.isTraceEnabled())
113 log.trace("Registered favicon " + faviconRelPath);
114
115 }
116
117 // page title
118 if (!properties.containsKey(WebClient.PAGE_TITLE))
119 properties.put(
120 WebClient.PAGE_TITLE,
121 Character.toUpperCase(page.charAt(0))
122 + page.substring(1));
123
124 // default body HTML
125 if (!properties.containsKey(WebClient.BODY_HTML))
126 properties.put(WebClient.BODY_HTML, DEFAULT_LOADING_BODY);
127
128 application.addEntryPoint("/" + page, new CmsEntryPointFactory(
129 page), properties);
130 log.info("Registered entry point /" + page);
131 }
132
133 // stylesheets
134 for (String themeId : styleSheets.keySet()) {
135 List<String> cssLst = styleSheets.get(themeId);
136 for (String css : cssLst) {
137 application.addStyleSheet(themeId, css,
138 new BundleResourceLoader(bundleContext));
139 }
140
141 }
142 } catch (RuntimeException e) {
143 // Easier access to initialisation errors
144 log.error("Unexpected exception when configuring RWT application.",
145 e);
146 throw e;
147 }
148 }
149
150 public void init() throws RepositoryException {
151 // if (workspace == null)
152 // throw new CmsException(
153 // "Workspace must be set when calling initialization."
154 // + " Please make sure that read-only and read-write roles"
155 // + " have been properly configured:"
156 // + " the defaults are open.");
157
158 Session session = null;
159 try {
160 session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
161 VersionManager vm = session.getWorkspace().getVersionManager();
162 if (!vm.isCheckedOut("/"))
163 vm.checkout("/");
164 JcrUtils.mkdirs(session, basePath);
165 for (String principal : rwPrincipals)
166 JcrUtils.addPrivilege(session, basePath, principal,
167 Privilege.JCR_WRITE);
168 for (String principal : roPrincipals)
169 JcrUtils.addPrivilege(session, basePath, principal,
170 Privilege.JCR_READ);
171
172 for (String pageName : pages.keySet()) {
173 try {
174 initPage(session, pages.get(pageName));
175 session.save();
176 } catch (Exception e) {
177 throw new CmsException(
178 "Cannot initialize page " + pageName, e);
179 }
180 }
181
182 } finally {
183 JcrUtils.logoutQuietly(session);
184 }
185 }
186
187 protected void initPage(Session adminSession, CmsUiProvider page)
188 throws RepositoryException {
189 if (page instanceof LifeCycleUiProvider)
190 ((LifeCycleUiProvider) page).init(adminSession);
191 }
192
193 public void destroy() {
194 for (String pageName : pages.keySet()) {
195 try {
196 CmsUiProvider page = pages.get(pageName);
197 if (page instanceof LifeCycleUiProvider)
198 ((LifeCycleUiProvider) page).destroy();
199 } catch (Exception e) {
200 log.error("Cannot destroy page " + pageName, e);
201 }
202 }
203 }
204
205 public void setRepository(Repository repository) {
206 this.repository = repository;
207 }
208
209 public void setWorkspace(String workspace) {
210 this.workspace = workspace;
211 }
212
213 public void setCmsLogin(CmsLogin cmsLogin) {
214 this.cmsLogin = cmsLogin;
215 }
216
217 public void setHeader(CmsUiProvider header) {
218 this.header = header;
219 }
220
221 public void setPages(Map<String, CmsUiProvider> pages) {
222 this.pages = pages;
223 }
224
225 public void setBasePath(String basePath) {
226 this.basePath = basePath;
227 }
228
229 public void setRoPrincipals(List<String> roPrincipals) {
230 this.roPrincipals = roPrincipals;
231 }
232
233 public void setRwPrincipals(List<String> rwPrincipals) {
234 this.rwPrincipals = rwPrincipals;
235 }
236
237 public void setHeaderHeight(Integer headerHeight) {
238 this.headerHeight = headerHeight;
239 }
240
241 // public void setEntryPoints(
242 // Map<String, EntryPointFactory> entryPointFactories) {
243 // this.entryPoints = entryPointFactories;
244 // }
245
246 public void setBranding(Map<String, Map<String, String>> branding) {
247 this.branding = branding;
248 }
249
250 public void setStyleSheets(Map<String, List<String>> styleSheets) {
251 this.styleSheets = styleSheets;
252 }
253
254 public void setBundleContext(BundleContext bundleContext) {
255 this.bundleContext = bundleContext;
256 }
257
258 public void setResources(List<String> resources) {
259 this.resources = resources;
260 }
261
262 class CmsExceptionHandler implements ExceptionHandler {
263
264 @Override
265 public void handleException(Throwable throwable) {
266 CmsSession.current.get().exception(throwable);
267 }
268
269 }
270
271 private class CmsEntryPointFactory implements EntryPointFactory {
272 private final String page;
273
274 public CmsEntryPointFactory(String page) {
275 this.page = page;
276 }
277
278 @Override
279 public EntryPoint create() {
280 CmsEntryPoint entryPoint = new CmsEntryPoint(repository, workspace,
281 pages.get(page));
282 entryPoint.setState("");
283 CmsSession.current.set(entryPoint);
284 return entryPoint;
285 }
286
287 }
288
289 private class CmsEntryPoint extends AbstractCmsEntryPoint {
290 private Composite headerArea;
291 private Composite bodyArea;
292 private final CmsUiProvider uiProvider;
293
294 public CmsEntryPoint(Repository repository, String workspace,
295 CmsUiProvider uiProvider) {
296 super(repository, workspace);
297 this.uiProvider = uiProvider;
298 }
299
300 @Override
301 protected void createContents(Composite parent) {
302 try {
303 getShell().getDisplay().setData(CmsSession.KEY, this);
304
305 parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
306 true));
307 parent.setLayout(CmsUtils.noSpaceGridLayout());
308
309 headerArea = new Composite(parent, SWT.NONE);
310 headerArea.setLayout(new FillLayout());
311 GridData headerData = new GridData(SWT.FILL, SWT.FILL, false,
312 false);
313 headerData.heightHint = headerHeight;
314 headerArea.setLayoutData(headerData);
315 refreshHeader();
316
317 bodyArea = new Composite(parent, SWT.NONE);
318 bodyArea.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_BODY);
319 bodyArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
320 true));
321 bodyArea.setBackgroundMode(SWT.INHERIT_DEFAULT);
322 bodyArea.setLayout(CmsUtils.noSpaceGridLayout());
323 refreshBody();
324 } catch (Exception e) {
325 throw new CmsException("Cannot create entrypoint contents", e);
326 }
327 }
328
329 @Override
330 protected void refreshHeader() {
331 if (headerArea == null)
332 return;
333 for (Control child : headerArea.getChildren())
334 child.dispose();
335 try {
336 header.createUi(headerArea, getNode());
337 } catch (RepositoryException e) {
338 throw new CmsException("Cannot refresh header", e);
339 }
340 headerArea.layout(true, true);
341 }
342
343 @Override
344 protected void refreshBody() {
345 if (bodyArea == null)
346 return;
347 // clear
348 for (Control child : bodyArea.getChildren())
349 child.dispose();
350 bodyArea.setLayout(CmsUtils.noSpaceGridLayout());
351
352 // Exception
353 Throwable exception = getException();
354 if (exception != null) {
355 new Label(bodyArea, SWT.NONE).setText("Unreachable state : "
356 + getState());
357 if (getNode() != null)
358 new Label(bodyArea, SWT.NONE).setText("Context : "
359 + getNode());
360
361 Text errorText = new Text(bodyArea, SWT.MULTI | SWT.H_SCROLL
362 | SWT.V_SCROLL);
363 errorText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
364 true));
365 StringWriter sw = new StringWriter();
366 exception.printStackTrace(new PrintWriter(sw));
367 errorText.setText(sw.toString());
368 IOUtils.closeQuietly(sw);
369 resetException();
370 // TODO report
371 } else {
372 String state = getState();
373 try {
374 if (state == null)
375 throw new CmsException("State cannot be null");
376 uiProvider.createUi(bodyArea, getNode());
377 // if (page == null)
378 // throw new CmsException("Page cannot be null");
379 // // else if (state.length() == 0)
380 // // log.debug("empty state");
381 // else if (pages.containsKey(page))
382 // pages.get(page).createUi(bodyArea, getNode());
383 // else {
384 // // try {
385 // // RWT.getResponse().sendError(404);
386 // // } catch (IOException e) {
387 // // log.error("Cannot send 404 code", e);
388 // // }
389 // throw new CmsException("Unsupported state " + state);
390 // }
391 } catch (RepositoryException e) {
392 throw new CmsException("Cannot refresh body", e);
393 }
394 }
395 bodyArea.layout(true, true);
396 }
397
398 @Override
399 protected void logAsAnonymous() {
400 cmsLogin.logInAsAnonymous();
401 }
402
403 @Override
404 protected Node getDefaultNode(Session session)
405 throws RepositoryException {
406 if (!session.hasPermission(basePath, "read")) {
407 if (session.getUserID().equals("anonymous"))
408 throw new CmsLoginRequiredException();
409 else
410 throw new CmsException("Unauthorized");
411 }
412 return session.getNode(basePath);
413 }
414
415 @Override
416 public CmsImageManager getImageManager() {
417 return imageManager;
418 }
419
420 }
421
422 private static ResourceLoader createResourceLoader(final String resourceName) {
423 return new ResourceLoader() {
424 public InputStream getResourceAsStream(String resourceName)
425 throws IOException {
426 return getClass().getClassLoader().getResourceAsStream(
427 resourceName);
428 }
429 };
430 }
431
432 /*
433 * TEXTS
434 */
435 private static String DEFAULT_LOADING_BODY = "<div"
436 + " style=\"position: absolute; left: 50%; top: 50%; margin: -32px -32px; width: 64px; height:64px\">"
437 + "<img src=\"./rwt-resources/icons/loading.gif\" width=\"32\" height=\"32\" style=\"margin: 16px 16px\"/>"
438 + "</div>";
439 }