diff --git a/basiclti-impl/src/java/org/sakaiproject/basiclti/impl/BasicLTIArchiveBean.java b/basiclti-impl/src/java/org/sakaiproject/basiclti/impl/BasicLTIArchiveBean.java new file mode 100644 index 0000000..33f32c5 --- /dev/null +++ b/basiclti-impl/src/java/org/sakaiproject/basiclti/impl/BasicLTIArchiveBean.java @@ -0,0 +1,144 @@ +package org.sakaiproject.basiclti.impl; + +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +public class BasicLTIArchiveBean { + private String pageTitle = null; + private String toolTitle = null; + private Properties siteToolProperties = new Properties(); + + public final static String ALIAS = "basicLTI"; + public final static String PAGE_TITLE = "pageTitle"; + public final static String TOOL_TITLE = "toolTitle"; + public final static String SITE_TOOL_PROPERTIES = "siteToolProperties"; + + private Log logger = LogFactory.getLog(BasicLTISecurityServiceImpl.class); + + public BasicLTIArchiveBean() + { + } + + public BasicLTIArchiveBean(Node basicLTI) throws Exception + { + // Parse basicLTI Element Node and populate fields in BasicLTI bean + // The only fields should be pageTitle, toolTitle and siteToolProperties + if(basicLTI.getChildNodes().getLength() != 3) + { + throw new Exception("Invalid number of child Nodes for basicLTI Node."); + } + for(int i=0; i < basicLTI.getChildNodes().getLength(); i++) + { + // This node is a child of node basicLTI + Node basicLTIChildNode = basicLTI.getChildNodes().item(i); + if(basicLTIChildNode.getNodeName().equals(BasicLTIArchiveBean.PAGE_TITLE)) + { + if(this.pageTitle != null) + { + throw new Exception("Multiple pageTitle Nodes nested within basicLTI Node."); + } + this.pageTitle = basicLTIChildNode.getTextContent(); + } + else if(basicLTIChildNode.getNodeName().equals(BasicLTIArchiveBean.TOOL_TITLE)) + { + if(this.toolTitle != null) + { + throw new Exception("Multiple toolTitle Nodes nested within basicLTI Node."); + } + this.toolTitle = basicLTIChildNode.getTextContent(); + } + else if(basicLTIChildNode.getNodeName().equals(BasicLTIArchiveBean.SITE_TOOL_PROPERTIES)) + { + // if siteToolProperties has already been populated + if(this.getSiteToolProperties().keySet().size() != 0) + { + throw new Exception("Multiple siteToolProperties Nodes nested within basicLTI Node."); + } + for(int j=0; j < basicLTIChildNode.getChildNodes().getLength(); j++) + { + Node propertyNode = basicLTIChildNode.getChildNodes().item(j); + String name = propertyNode.getAttributes().getNamedItem("name").getTextContent(); + String value = propertyNode.getAttributes().getNamedItem("value").getTextContent(); + if(this.getSiteToolProperties().containsKey(name)) + { + throw new Exception("Duplicate property " + name); + } + this.getSiteToolProperties().setProperty(name, value); + } + } + else + { + throw new Exception("Unrecognized Node " + basicLTIChildNode.getNodeName() + " in basicLTI Node"); + } + } + } + + public String getPageTitle() + { + return this.pageTitle; + } + + public String getToolTitle() + { + return this.toolTitle; + } + + public void setPageTitle(String title) + { + this.pageTitle = title; + } + + public void setToolTitle(String title) + { + this.toolTitle = title; + } + + public Properties getSiteToolProperties() + { + return this.siteToolProperties; + } + + public void setSiteToolProperties(Properties siteToolProperties) + { + this.siteToolProperties = siteToolProperties; + } + + public Node toNode(Document doc) + { + Node node = null; + logger.debug("Building node for " + this.getPageTitle()); + // The alias is the name of the root element -- basicLTI + // Look at the XStream documentation to see why I chose the term "alias" + node = doc.createElement(BasicLTIArchiveBean.ALIAS); + + Node pageTitleNode = doc.createElement(BasicLTIArchiveBean.PAGE_TITLE); + pageTitleNode.setTextContent(this.getPageTitle()); + node.appendChild(pageTitleNode); + + Node toolTitleNode = doc.createElement(BasicLTIArchiveBean.TOOL_TITLE); + toolTitleNode.setTextContent(this.getToolTitle()); + node.appendChild(toolTitleNode); + + Node propertiesNode = doc.createElement(BasicLTIArchiveBean.SITE_TOOL_PROPERTIES); + for(Object key: this.getSiteToolProperties().keySet()) + { + Attr name = doc.createAttribute("name"); + name.setValue((String)key); + Attr value = doc.createAttribute("value"); + value.setValue(this.getSiteToolProperties().getProperty((String)key)); + + Node property = doc.createElement("property"); + property.getAttributes().setNamedItem(name); + property.getAttributes().setNamedItem(value); + propertiesNode.appendChild(property); + } + node.appendChild(propertiesNode); + return node; + } +} \ No newline at end of file diff --git a/basiclti-impl/src/java/org/sakaiproject/basiclti/impl/BasicLTISecurityServiceImpl.java b/basiclti-impl/src/java/org/sakaiproject/basiclti/impl/BasicLTISecurityServiceImpl.java index ac3fa90..9f876e8 100644 --- a/basiclti-impl/src/java/org/sakaiproject/basiclti/impl/BasicLTISecurityServiceImpl.java +++ b/basiclti-impl/src/java/org/sakaiproject/basiclti/impl/BasicLTISecurityServiceImpl.java @@ -31,7 +31,9 @@ import javax.servlet.ServletOutputStream; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.authz.cover.SecurityService; @@ -46,8 +48,10 @@ import org.sakaiproject.entity.api.HttpAccess; import org.sakaiproject.entity.api.Reference; import org.sakaiproject.entity.api.ResourceProperties; import org.sakaiproject.tool.cover.SessionManager; +import org.sakaiproject.tool.cover.ToolManager; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.cover.SiteService; +import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.util.StringUtil; import org.sakaiproject.exception.IdUnusedException; @@ -60,21 +64,26 @@ import org.sakaiproject.lti.api.LTIService; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.util.Validator; import org.sakaiproject.util.Web; +import org.sakaiproject.site.api.SitePage; +import org.sakaiproject.site.api.ToolConfiguration; import org.sakaiproject.util.foorm.SakaiFoorm; import org.sakaiproject.basiclti.LocalEventTrackingService; import org.sakaiproject.basiclti.util.SakaiBLTIUtil; +import org.sakaiproject.basiclti.impl.BasicLTIArchiveBean; @SuppressWarnings("deprecation") public class BasicLTISecurityServiceImpl implements EntityProducer { + public static final String SERVICE_NAME = BasicLTISecurityServiceImpl.class.getName(); private static ResourceLoader rb = new ResourceLoader("basicltisvc"); public static final String MIME_TYPE_BLTI="ims/basiclti"; public static final String REFERENCE_ROOT="/basiclti"; public static final String APPLICATION_ID = "sakai:basiclti"; + public static final String TOOL_REGISTRATION = "sakai.basiclti"; public static final String EVENT_BASICLTI_LAUNCH = "basiclti.launch"; protected static SakaiFoorm foorm = new SakaiFoorm(); @@ -212,7 +221,7 @@ public class BasicLTISecurityServiceImpl implements EntityProducer { res.addDateHeader("Last-Modified", System.currentTimeMillis()); res.addHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0"); res.addHeader("Pragma", "no-cache"); - ServletOutputStream out = res.getOutputStream(); + java.io.PrintWriter out = res.getWriter(); out.println(""); out.println(""); @@ -388,20 +397,95 @@ public class BasicLTISecurityServiceImpl implements EntityProducer { public boolean willArchiveMerge() { - return false; + return true; } @SuppressWarnings("unchecked") public String merge(String siteId, Element root, String archivePath, String fromSiteId, Map attachmentNames, Map userIdTrans, Set userListAllowImport) { - return null; + StringBuilder results = new StringBuilder("Merging BasicLTI "); + org.w3c.dom.NodeList nodeList = root.getElementsByTagName("basicLTI"); + + try { + Site site = SiteService.getSite(siteId); + + for(int i=0; i < nodeList.getLength(); i++) + { + BasicLTIArchiveBean basicLTI = new BasicLTIArchiveBean(nodeList.item(i)); + logger.info("BASIC LTI: " + basicLTI); + results.append(", merging basicLTI tool " + basicLTI.getPageTitle()); + + SitePage sitePage = site.addPage(); + sitePage.setTitle(basicLTI.getPageTitle()); + // This property affects both the Tool and SitePage. + sitePage.setTitleCustom(true); + + ToolConfiguration toolConfiguration = sitePage.addTool(); + toolConfiguration.setTool(TOOL_REGISTRATION, ToolManager.getTool(TOOL_REGISTRATION)); + toolConfiguration.setTitle(basicLTI.getToolTitle()); + + for(Object key: basicLTI.getSiteToolProperties().keySet()) + { + toolConfiguration.getPlacementConfig().setProperty((String)key, (String)basicLTI.getSiteToolProperties().get(key)); + } + + SiteService.save(site); + } + } catch (IdUnusedException ie) { + // This would be thrown by SiteService.getSite(siteId) + ie.printStackTrace(); + } catch (PermissionException pe) { + // This would be thrown by SiteService.save(site) + pe.printStackTrace(); + } catch (Exception e) { + // This is a generic exception that would be thrown by the BasicLTIArchiveBean constructor. + e.printStackTrace(); + } + + results.append("."); + return results.toString(); } @SuppressWarnings("unchecked") public String archive(String siteId, Document doc, Stack stack, String archivePath, List attachments) { - return null; - } + logger.info("-------basic-lti-------- archive('" + + StringUtils.join(new Object[] { siteId, doc, stack, + archivePath, attachments }, "','") + "')"); + + StringBuilder results = new StringBuilder("Archiving BasicLTI "); + + try { + Site site = SiteService.getSite(siteId); + logger.info("SITE: " + site.getId() + " : " + site.getTitle()); + Element basicLtiList = doc.createElement("org.sakaiproject.basiclti.service.BasicLTISecurityService"); + + for (SitePage sitePage : site.getPages()) { + for (ToolConfiguration toolConfiguration : sitePage.getTools()) { + if (toolConfiguration.getTool().getId().equals( + TOOL_REGISTRATION)) { + results.append("archiving BasicLTI tool " + toolConfiguration.getId()); + + BasicLTIArchiveBean basicLTIArchiveBean = new BasicLTIArchiveBean(); + basicLTIArchiveBean.setPageTitle(sitePage.getTitle()); + basicLTIArchiveBean.setToolTitle(toolConfiguration.getTitle()); + basicLTIArchiveBean.setSiteToolProperties(toolConfiguration.getConfig()); + + Node newNode = basicLTIArchiveBean.toNode(doc); + basicLtiList.appendChild(newNode); + } + } + } + + ((Element) stack.peek()).appendChild(basicLtiList); + stack.push(basicLtiList); + stack.pop(); + } + catch (IdUnusedException iue) { + logger.info("SITE ID " + siteId + " DOES NOT EXIST."); + } + return results.toString(); + } } -- 1.7.4.1