]> git.argeo.org Git - lgpl/argeo-commons.git/blob - AbstractCmsEntryPoint.java
6722d7b86291051c61b39fc286f88d136ebc3a55
[lgpl/argeo-commons.git] / AbstractCmsEntryPoint.java
1 package org.argeo.cms;
2
3 import java.util.Locale;
4 import java.util.ResourceBundle;
5
6 import javax.jcr.Node;
7 import javax.jcr.Repository;
8 import javax.jcr.RepositoryException;
9 import javax.jcr.Session;
10 import javax.jcr.nodetype.NodeType;
11
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14 import org.argeo.jcr.JcrUtils;
15 import org.eclipse.rap.rwt.RWT;
16 import org.eclipse.rap.rwt.application.AbstractEntryPoint;
17 import org.eclipse.rap.rwt.client.service.BrowserNavigation;
18 import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent;
19 import org.eclipse.rap.rwt.client.service.BrowserNavigationListener;
20 import org.eclipse.swt.widgets.Display;
21 import org.eclipse.swt.widgets.Shell;
22 import org.springframework.security.core.context.SecurityContext;
23 import org.springframework.security.core.context.SecurityContextHolder;
24
25 /** Manages history and navigation */
26 public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint
27 implements CmsSession {
28 private final Log log = LogFactory.getLog(AbstractCmsEntryPoint.class);
29 private static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
30
31 private Repository repository;
32 private String workspace;
33 private Session session;
34
35 // current state
36 private Node node;
37 private String state;
38 private String page;
39 private Throwable exception;
40
41 private BrowserNavigation history;
42
43 public AbstractCmsEntryPoint(Repository repository, String workspace) {
44 if (SecurityContextHolder.getContext().getAuthentication() == null) {
45 SecurityContext contextFromSessionObject = (SecurityContext) RWT
46 .getRequest().getSession()
47 .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
48 if (contextFromSessionObject != null)
49 SecurityContextHolder.setContext(contextFromSessionObject);
50 else
51 logAsAnonymous();
52 }
53
54 this.repository = repository;
55 this.workspace = workspace;
56 authChange();
57
58 history = RWT.getClient().getService(BrowserNavigation.class);
59 if (history != null)
60 history.addBrowserNavigationListener(new CmsNavigationListener());
61
62 // RWT.setLocale(Locale.FRANCE);
63 }
64
65 @Override
66 protected Shell createShell(Display display) {
67 Shell shell = super.createShell(display);
68 shell.setData(RWT.CUSTOM_VARIANT, CmsStyles.CMS_SHELL);
69 display.disposeExec(new Runnable() {
70
71 @Override
72 public void run() {
73 if (log.isTraceEnabled())
74 log.trace("Logging out " + session);
75 JcrUtils.logoutQuietly(session);
76 }
77 });
78 return shell;
79 }
80
81 /** Recreate header UI */
82 protected abstract void refreshHeader();
83
84 /** Recreate body UI */
85 protected abstract void refreshBody();
86
87 /** Log as anonymous */
88 protected abstract void logAsAnonymous();
89
90 /**
91 * The node to return when no node was found (for authenticated users and
92 * anonymous)
93 */
94 protected abstract Node getDefaultNode(Session session)
95 throws RepositoryException;
96
97 /**
98 * Reasonable default since it is a nt:hierarchyNode and is thus compatible
99 * with the obvious default folder type, nt:folder, conceptual equivalent of
100 * an empty text file in an operating system. To be overridden.
101 */
102 protected String getDefaultNewNodeType() {
103 return CmsTypes.CMS_TEXT;
104 }
105
106 /** Default new folder type (used in mkdirs) is nt:folder. To be overridden. */
107 protected String getDefaultNewFolderType() {
108 return NodeType.NT_FOLDER;
109 }
110
111 public void navigateTo(String state) {
112 exception = null;
113 setState(state);
114 refreshBody();
115 if (history != null)
116 history.pushState(state, state);
117 }
118
119 @Override
120 public void authChange() {
121 try {
122 String currentPath = null;
123 if (node != null)
124 currentPath = node.getPath();
125 JcrUtils.logoutQuietly(session);
126
127 if (SecurityContextHolder.getContext().getAuthentication() == null)
128 logAsAnonymous();
129 session = repository.login(workspace);
130 if (currentPath != null)
131 node = session.getNode(currentPath);
132
133 // refresh UI
134 refreshHeader();
135 refreshBody();
136 } catch (RepositoryException e) {
137 throw new CmsException("Cannot perform auth change", e);
138 }
139
140 }
141
142 @Override
143 public void exception(Throwable e) {
144 this.exception = e;
145 log.error("Unexpected exception in CMS", e);
146 refreshBody();
147 }
148
149 @Override
150 public Object local(Msg msg) {
151 String key = msg.getId();
152 int lastDot = key.lastIndexOf('.');
153 String className = key.substring(0, lastDot);
154 String fieldName = key.substring(lastDot + 1);
155 Locale locale = RWT.getLocale();
156 ResourceBundle rb = ResourceBundle.getBundle(className, locale,
157 msg.getClassLoader());
158 return rb.getString(fieldName);
159 }
160
161 /** Sets the state of the entry point and retrieve the related JCR node. */
162 protected synchronized void setState(String newState) {
163 String previousState = this.state;
164
165 node = null;
166 page = null;
167 this.state = newState;
168
169 try {
170 int firstSlash = state.indexOf('/');
171 if (firstSlash == 0) {
172 if (!session.nodeExists(state))
173 node = addNode(session, state, null);
174 else
175 node = session.getNode(state);
176 page = "";
177 } else if (firstSlash > 0) {
178 String prefix = state.substring(0, firstSlash);
179 String path = state.substring(firstSlash);
180 if (session.getWorkspace().getNodeTypeManager()
181 .hasNodeType(prefix)) {
182 String nodeType = prefix;
183 if (!session.nodeExists(path))
184 node = addNode(session, path, nodeType);
185 else {
186 node = session.getNode(path);
187 if (!node.isNodeType(nodeType))
188 throw new CmsException("Node " + path
189 + " not of type " + nodeType);
190 }
191 } else if ("delete".equals(prefix)) {
192 if (session.itemExists(path)) {
193 Node nodeToDelete = session.getNode(path);
194 // TODO "Are you sure?"
195 nodeToDelete.remove();
196 session.save();
197 log.debug("Deleted " + path);
198 navigateTo(previousState);
199 } else
200 throw new CmsException("Data " + path
201 + " does not exist");
202 } else {
203 if (session.itemExists(path))
204 node = session.getNode(path);
205 else
206 throw new CmsException("Data " + path
207 + " does not exist");
208 }
209 page = prefix;
210 } else {
211 node = getDefaultNode(session);
212 if (state.equals("~"))
213 page = "";
214 else
215 page = state;
216 }
217
218 if (log.isTraceEnabled())
219 log.trace("page=" + page + ", node=" + node + ", state="
220 + state);
221
222 } catch (RepositoryException e) {
223 throw new CmsException("Cannot retrieve node", e);
224 }
225 }
226
227 protected Node addNode(Session session, String path, String nodeType)
228 throws RepositoryException {
229 return JcrUtils.mkdirs(session, path, nodeType != null ? nodeType
230 : getDefaultNewNodeType(), getDefaultNewFolderType(), false);
231 // not saved, so that the UI can discard it later on
232 }
233
234 protected Node getNode() {
235 return node;
236 }
237
238 @Override
239 public String getState() {
240 return state;
241 }
242
243 protected String getPage() {
244 return page;
245 }
246
247 protected Throwable getException() {
248 return exception;
249 }
250
251 protected void resetException() {
252 exception = null;
253 }
254
255 protected Session getSession() {
256 return session;
257 }
258
259 private class CmsNavigationListener implements BrowserNavigationListener {
260 private static final long serialVersionUID = -3591018803430389270L;
261
262 @Override
263 public void navigated(BrowserNavigationEvent event) {
264 setState(event.getState());
265 refreshBody();
266 }
267 }
268
269 }