001: /* Copyright 2006 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.layout.dlm.publisher;
007:
008: import java.io.File;
009: import java.sql.Connection;
010: import java.sql.PreparedStatement;
011: import java.sql.ResultSet;
012: import java.sql.SQLException;
013: import java.util.Enumeration;
014:
015: import javax.xml.parsers.DocumentBuilder;
016: import javax.xml.parsers.DocumentBuilderFactory;
017: import javax.xml.xpath.XPath;
018: import javax.xml.xpath.XPathConstants;
019: import javax.xml.xpath.XPathFactory;
020:
021: import org.apache.commons.logging.Log;
022: import org.apache.commons.logging.LogFactory;
023:
024: import org.jasig.portal.ChannelDefinition;
025: import org.jasig.portal.ChannelRegistryStoreFactory;
026: import org.jasig.portal.IChannelRegistryStore;
027: import org.jasig.portal.RDBMServices;
028: import org.jasig.portal.StructureStylesheetUserPreferences;
029: import org.jasig.portal.UserProfile;
030: import org.jasig.portal.i18n.LocaleManager;
031: import org.jasig.portal.layout.IUserLayout;
032: import org.jasig.portal.layout.IUserLayoutManager;
033: import org.jasig.portal.layout.IUserLayoutStore;
034: import org.jasig.portal.layout.TransientUserLayoutManagerWrapper;
035: import org.jasig.portal.layout.UserLayoutManagerFactory;
036: import org.jasig.portal.layout.dlm.RDBMDistributedLayoutStore;
037: import org.jasig.portal.layout.node.IUserLayoutChannelDescription;
038: import org.jasig.portal.layout.node.IUserLayoutFolderDescription;
039: import org.jasig.portal.layout.node.IUserLayoutNodeDescription;
040: import org.jasig.portal.layout.node.UserLayoutChannelDescription;
041: import org.jasig.portal.layout.node.UserLayoutFolderDescription;
042: import org.jasig.portal.security.IPerson;
043: import org.jasig.portal.security.PersonFactory;
044: import org.w3c.dom.Attr;
045: import org.w3c.dom.Document;
046: import org.w3c.dom.Element;
047: import org.w3c.dom.NodeList;
048:
049: public class DlmLayoutPublisher {
050:
051: // Static Members.
052: private static final Log log = LogFactory
053: .getLog(DlmLayoutPublisher.class);
054: private static final int PROFILE_ID = 1;
055: private static final int LAYOUT_ID = 1;
056: private static final int STYLESHEET_ID = 4;
057: private static final int THEME_ID = 3;
058:
059: public static void main(String[] args) {
060:
061: // PrintWriter out = new PrintWriter(System.out);
062: log.info("DLM Layout Publisher Tool");
063: log.info("");
064:
065: switch (args.length) {
066: case 1:
067:
068: try {
069:
070: // Ensure the argument is a valid path...
071: File f = new File(args[0]);
072: if (!f.exists()) {
073: log.error("The specified file does not exist: "
074: + f.toString());
075: throw new IllegalArgumentException();
076: }
077:
078: // Make sure uPortal doesn't try to get a data source from the container...
079: RDBMServices.setGetDatasourceFromJndi(false);
080:
081: // Set up the layout store...
082: IUserLayoutStore store = new RDBMDistributedLayoutStore();
083:
084: // Choose between single or multiple files...
085: File[] layoutFiles = null;
086: if (f.isFile()) {
087: layoutFiles = new File[] { f };
088: } else if (f.isDirectory()) {
089: layoutFiles = f.listFiles();
090: }
091:
092: for (int i = 0; i < layoutFiles.length; i++) {
093:
094: if (!layoutFiles[i].isFile()) {
095: continue;
096: }
097:
098: // Read the document...
099: DocumentBuilderFactory builderFactory = DocumentBuilderFactory
100: .newInstance();
101: DocumentBuilder builder = builderFactory
102: .newDocumentBuilder();
103:
104: Document doc = builder.parse(layoutFiles[i]);
105:
106: // Obtain the specified user...
107: XPath xp = XPathFactory.newInstance().newXPath();
108:
109: Attr userAttr = (Attr) xp.evaluate(
110: "//layout/@user", doc, XPathConstants.NODE);
111: String uName = userAttr.getNodeValue();
112: System.out.print("Importing layout for user '"
113: + uName + "'...");
114: int uId = lookupUserId(uName);
115: IPerson usr = PersonFactory.createGuestPerson();
116: usr.setAttribute(IPerson.USERNAME, uName);
117: usr.setID(uId);
118:
119: // Construct the layout manager...
120: UserProfile prf = new UserProfile(PROFILE_ID,
121: "User Profile for " + uName,
122: "User Profile", LAYOUT_ID, STYLESHEET_ID,
123: THEME_ID);
124: LocaleManager lm = new LocaleManager(usr);
125: prf.setLocaleManager(lm);
126: IUserLayoutManager dlm = ((TransientUserLayoutManagerWrapper) UserLayoutManagerFactory
127: .getUserLayoutManager(usr, prf))
128: .getOriginalLayoutManager();
129:
130: // Retrieve the layout...
131: StructureStylesheetUserPreferences ssup = store
132: .getStructureStylesheetUserPreferences(usr,
133: PROFILE_ID, STYLESHEET_ID);
134: IUserLayout layout = dlm.getUserLayout();
135: IUserLayoutNodeDescription root = layout
136: .getNodeDescription(layout.getRootId());
137:
138: // First clear the existing layout (if any) down to the root folder...
139: for (Enumeration e = dlm.getChildIds(root.getId()); e
140: .hasMoreElements();) {
141: String chldId = (String) e.nextElement();
142: IUserLayoutNodeDescription chldNd = dlm
143: .getNode(chldId);
144: chldNd.setDeleteAllowed(true); // just to be sure...
145: chldNd.setEditAllowed(true);
146: if (!dlm.updateNode(chldNd)
147: || !dlm.deleteNode(chldId)) {
148: String msg = "Unable to update/delete a layout node: "
149: + chldNd.getName();
150: throw new RuntimeException(msg);
151: }
152: }
153:
154: // Construct the new layout contents...
155: NodeList list = (NodeList) xp.evaluate(
156: "//layout/root-folder/folder", doc,
157: XPathConstants.NODESET);
158: String idLast = null;
159: for (int j = list.getLength() - 1; j >= 0; j--) {
160: Element e = (Element) list.item(j);
161: IUserLayoutFolderDescription fld = createFolder(
162: e, ssup, dlm, layout.getRootId(),
163: idLast);
164: idLast = fld.getId();
165: }
166:
167: // Save the layout...
168: dlm.saveUserLayout();
169: store.setStructureStylesheetUserPreferences(usr,
170: PROFILE_ID, ssup);
171:
172: System.out.println("done!");
173:
174: }
175:
176: } catch (Throwable t) {
177: log.error(
178: "The publisher tool terminated unexpectedly.",
179: t);
180: System.out
181: .println("The publisher tool terminated unexpectedly.");
182: t.printStackTrace(System.out);
183: System.exit(7);
184: }
185:
186: break;
187:
188: default:
189:
190: log
191: .info("Usage: java org.jasig.portal.layout.dlm.publisher <layout_definition_path>");
192: log.info("");
193: log
194: .info("where <layout_definition_path> is the path (full or ");
195: log
196: .info("relative) to a valid layout definition XML file.");
197: break;
198:
199: }
200:
201: log.info("The publisher tool completed successfully.");
202: System.exit(0);
203:
204: }
205:
206: public static int lookupUserId(String uName) {
207:
208: // Assertions.
209: if (uName == null) {
210: String msg = "Argument 'uName' cannot be null.";
211: throw new IllegalArgumentException(msg);
212: }
213:
214: // NB: It royally stinks that uPortal does not
215: // provide an API call to obtaun this information.
216:
217: int rslt = -1;
218:
219: Connection conn = null;
220: PreparedStatement pstmt = null;
221: ResultSet rs = null;
222:
223: try {
224:
225: conn = RDBMServices.getConnection();
226:
227: final String sql = "SELECT user_id FROM up_user WHERE user_name = ?";
228:
229: pstmt = conn.prepareStatement(sql);
230: pstmt.setString(1, uName);
231:
232: rs = pstmt.executeQuery();
233: if (rs.next()) {
234: rslt = rs.getInt(1);
235: } else {
236: // this is a problem...
237: String msg = "User name not found in the database: "
238: + uName;
239: throw new RuntimeException(msg);
240: }
241:
242: } catch (Throwable t) {
243: String msg = "Error encountered looking up the specified user: "
244: + uName;
245: throw new RuntimeException(msg, t);
246: } finally {
247:
248: try {
249: if (pstmt != null)
250: pstmt.close();
251: } catch (SQLException sqle) { /* not much we can do... */
252: }
253:
254: try {
255: if (conn != null)
256: RDBMServices.releaseConnection(conn);
257: } catch (Throwable t) { /* not much we can do... */
258: }
259:
260: }
261:
262: return rslt;
263:
264: }
265:
266: private static IUserLayoutFolderDescription createFolder(Element e,
267: StructureStylesheetUserPreferences ssup,
268: IUserLayoutManager dlm, String parentId, String nextId) {
269:
270: XPath xp = XPathFactory.newInstance().newXPath();
271:
272: // Assertions.
273: if (e == null) {
274: String msg = "Argument 'e [Element]' cannot be null.";
275: throw new IllegalArgumentException(msg);
276: }
277: if (!e.getTagName().equals("folder")) {
278: String msg = "Argument 'e [Element]' must be a <folder> element.";
279: throw new IllegalArgumentException(msg);
280: }
281: if (ssup == null) {
282: String msg = "Argument 'ssup' cannot be null.";
283: throw new IllegalArgumentException(msg);
284: }
285: if (dlm == null) {
286: String msg = "Argument 'dlm' cannot be null.";
287: throw new IllegalArgumentException(msg);
288: }
289: if (parentId == null) {
290: String msg = "Argument 'parentId' cannot be null.";
291: throw new IllegalArgumentException(msg);
292: }
293: // NB: Argument 'nextId' may be null.
294:
295: UserLayoutFolderDescription rslt = new UserLayoutFolderDescription();
296:
297: try {
298:
299: // evaluate the folder type...
300: String typeName = e.getAttribute("type");
301: int type = -1;
302: if (typeName.equalsIgnoreCase("header")) {
303: type = UserLayoutFolderDescription.HEADER_TYPE;
304: } else if (typeName.equalsIgnoreCase("regular")) {
305: type = UserLayoutFolderDescription.REGULAR_TYPE;
306: } else if (typeName.equalsIgnoreCase("footer")) {
307: type = UserLayoutFolderDescription.FOOTER_TYPE;
308: }
309: if (type != -1) {
310: rslt.setFolderType(type);
311: }
312:
313: // evaluate the other settings...
314: rslt.setAddChildAllowed(true);
315: rslt.setDeleteAllowed(e.getAttribute("removable")
316: .equalsIgnoreCase("true"));
317: rslt.setEditAllowed(e.getAttribute("mutable")
318: .equalsIgnoreCase("true"));
319: rslt.setImmutable(e.getAttribute("mutable")
320: .equalsIgnoreCase("false"));
321:
322: rslt.setName(xp.evaluate("name", e));
323: rslt.setUnremovable(e.getAttribute("removable")
324: .equalsIgnoreCase("false"));
325:
326: // Add the node to the layout...
327: rslt = (UserLayoutFolderDescription) dlm.addNode(rslt,
328: parentId, nextId);
329:
330: // Add width if present...
331: String width = e.getAttribute("width");
332: if (!width.equals("")) {
333: ssup.addFolder(rslt.getId());
334: ssup.setFolderAttributeValue(rslt.getId(), "width",
335: width);
336: }
337:
338: // evaluate children...
339: NodeList chld = (NodeList) xp.evaluate("folder", e,
340: XPathConstants.NODESET);
341: String idLast = null;
342: for (int i = chld.getLength() - 1; i >= 0; i--) {
343: Element elmNow = (Element) chld.item(i);
344: IUserLayoutFolderDescription fld = createFolder(elmNow,
345: ssup, dlm, rslt.getId(), idLast);
346: idLast = fld.getId();
347: }
348:
349: // channels...
350: chld = (NodeList) xp.evaluate("channel", e,
351: XPathConstants.NODESET);
352: idLast = null;
353: for (int i = chld.getLength() - 1; i >= 0; i--) {
354: Element elmNow = (Element) chld.item(i);
355: IUserLayoutChannelDescription chn = createChannel(
356: elmNow, dlm, rslt.getId(), idLast);
357: idLast = chn.getId();
358: }
359:
360: } catch (Throwable t) {
361: String msg = "Unable to create the specified folder: "
362: + e.getTextContent();
363: throw new RuntimeException(msg, t);
364: }
365:
366: return rslt;
367:
368: }
369:
370: private static IUserLayoutChannelDescription createChannel(
371: Element e, IUserLayoutManager dlm, String parentId,
372: String nextId) {
373:
374: // Assertions.
375: if (e == null) {
376: String msg = "Argument 'e [Element]' cannot be null.";
377: throw new IllegalArgumentException(msg);
378: }
379: if (!e.getNodeName().equals("channel")) {
380: String msg = "Argument 'e [Element]' must be a <channel> element.";
381: throw new IllegalArgumentException(msg);
382: }
383: if (dlm == null) {
384: String msg = "Argument 'dlm' cannot be null.";
385: throw new IllegalArgumentException(msg);
386: }
387: if (parentId == null) {
388: String msg = "Argument 'parentId' cannot be null.";
389: throw new IllegalArgumentException(msg);
390: }
391: // NB: Argument 'nextId' may be null.
392:
393: // First obtain the referenced ChannelDefinition...
394: String fName = e.getAttribute("fName");
395: ChannelDefinition def = null;
396: try {
397:
398: IChannelRegistryStore store = ChannelRegistryStoreFactory
399: .getChannelRegistryStoreImpl();
400: def = store.getChannelDefinition(fName);
401:
402: if (def == null) {
403: String msg = "The specified channel definition does not exist in the system: "
404: + fName;
405: throw new RuntimeException(msg);
406: }
407:
408: } catch (Throwable t) {
409: String msg = "Error encountered with the specified channel definition: "
410: + fName;
411: throw new RuntimeException(msg, t);
412: }
413:
414: // Create the ChannelDescription...
415: UserLayoutChannelDescription rslt = new UserLayoutChannelDescription();
416: try {
417:
418: // channel settings...
419: rslt.setChannelPublishId(Integer.toString(def.getId()));
420: rslt.setChannelTypeId(Integer.toString(def.getTypeId()));
421: rslt.setClassName(def.getJavaClass());
422: rslt.setDescription(def.getDescription());
423: rslt.setEditable(def.isEditable());
424: rslt.setFunctionalName(fName);
425: rslt.setHasAbout(def.hasAbout());
426: rslt.setHasHelp(def.hasHelp());
427: rslt.setIsSecure(def.isSecure());
428: rslt.setTimeout(def.getTimeout());
429: rslt.setTitle(def.getTitle());
430:
431: // layout node settings...
432: rslt.setAddChildAllowed(false);
433: rslt.setDeleteAllowed(true);
434: rslt.setEditAllowed(true);
435: rslt.setImmutable(false);
436: rslt.setMoveAllowed(true);
437: rslt.setName(null);
438: rslt.setUnremovable(false);
439:
440: // Add the node to the layout...
441: rslt = (UserLayoutChannelDescription) dlm.addNode(rslt,
442: parentId, nextId);
443:
444: } catch (Throwable t) {
445: String msg = "Unable to create the specified channel: "
446: + fName;
447: throw new RuntimeException(msg, t);
448: }
449:
450: return rslt;
451:
452: }
453:
454: }
|