contents = contentLoader.loadListById(courseToc.getContentId());
+ // iterate through the content items in this content object
+ for (Content content : contents) {
+ // only LAMS content
+ if ("resource/x-lams-lamscontent".equals(content.getContentHandler())) {
+
+ PkId contentId = (PkId) content.getId();
+ String _content_id = "_" + contentId.getPk1() + "_" + contentId.getPk2();
+
+ String url = content.getUrl();
+ String urlLessonId = getParameterValue(url, "lsid");
+ String urlCourseId = getParameterValue(url, "course_id");
+ String urlContentId = getParameterValue(url, "content_id");
+ String urlLdId = getParameterValue(url, "ldid");
+
+ //in case when both courseId and contentId don't coincide with the ones from URL - means lesson needs to be imported
+ if (!urlCourseId.equals(_course_id) && !urlContentId.equals(_content_id)) {
+
+ final Long newLdId = LamsSecurityUtil.importLearningDesign(teacher, courseIdParam, urlLessonId,
+ urlLdId);
+
+ logger.debug("Lesson (lessonId=" + urlLessonId
+ + ") was successfully imported to the one (learningDesignId=" + newLdId + ").");
+
+ // Start the Lesson in LAMS (via Webservices) and capture the lesson ID
+ String teacherUsername = teacher.getUserName();
+ String title = content.getTitle();
+ FormattedText descriptionFormatted = content.getBody();
+ String description = URLEncoder.encode(descriptionFormatted.getText(), "UTF-8");
+ final long newLessonId = LamsSecurityUtil.startLesson(ctx, teacherUsername,
+ courseIdParam, newLdId, title, description, false);
+
+ // update lesson id
+ content.setLinkRef(Long.toString(newLessonId));
+
+ // update URL
+ url = replaceParameterValue(url, "lsid", Long.toString(newLessonId));
+ url = replaceParameterValue(url, "course_id", _course_id);
+ url = replaceParameterValue(url, "content_id", _content_id);
+ content.setUrl(url);
+
+ // persist updated content
+ persister.persist(content);
+
+ // store internalContentId -> externalContentId. It's used for lineitem removal (delete.jsp)
+ PortalExtraInfo pei = PortalUtil.loadPortalExtraInfo(null, null, "LamsStorage");
+ ExtraInfo ei = pei.getExtraInfo();
+ ei.setValue(_content_id, Long.toString(newLessonId));
+ PortalUtil.savePortalExtraInfo(pei);
+
+ // Gradebook column will be copied automatically if appropriate option is selected on
+ // importing lesson page
+
+ logger.debug("Lesson (lessonId=" + urlLessonId
+ + ") was successfully imported to the one (lessonId=" + newLessonId + ").");
+
+ newLessonIds += newLessonId + ", ";
+ }
+ }
+
+ }
+ }
+ }
+
+ } catch (LamsServerException e) {
+ //printing out error cause
+ response.setContentType("text/html");
+ PrintWriter out = response.getWriter();
+ out.write("Failed! " + e.getMessage());
+ out.flush();
+ out.close();
+ return;
+ } catch (IllegalStateException e) {
+ throw new ServletException(
+ "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator",
+ e);
+ } catch (InitializationException e) {
+ throw new ServletException(e);
+ } catch (BbServiceException e) {
+ throw new ServletException(e);
+ } catch (Exception e) {
+ throw new ServletException(e);
+ }
+
+ //prepare string to write out
+ int newLessonsCounts = newLessonIds.length() - newLessonIds.replace(",", "").length();
+ String resultStr = "Complete! " + newLessonsCounts + " lessons have been imported.";
+ //add all lessonIds (without the last comma)
+ if (newLessonsCounts > 0) {
+ resultStr += " Their updated lessonIds: " + newLessonIds.substring(0, newLessonIds.length()-2);
+ }
+ logger.debug(resultStr);
+
+ response.setContentType("text/html");
+ PrintWriter out = response.getWriter();
+ out.write(resultStr);
+ out.flush();
+ out.close();
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ doGet(req, resp);
+ }
+
+ /*
+ * Returns param value, and empty string in case of there is no such param available
+ *
+ * @param url
+ * @param paramName
+ * @return
+ */
+ private static String getParameterValue(String url, String paramName) {
+ String paramValue = "";
+
+ int quotationMarkIndex = url.indexOf("?");
+ String queryPart = quotationMarkIndex > -1 ? url.substring(quotationMarkIndex + 1) : url;
+ String[] paramEntries = queryPart.split("&");
+ for (String paramEntry : paramEntries) {
+ String[] paramEntrySplitted = paramEntry.split("=");
+ if ((paramEntrySplitted.length > 1) && paramName.equalsIgnoreCase(paramEntrySplitted[0])) {
+ paramValue = paramEntrySplitted[1];
+ break;
+ }
+ }
+
+ return paramValue;
+ }
+
+ private static String replaceParameterValue(String url, String paramName, String newParamValue) {
+ String oldParamValue = "";
+
+ int quotationMarkIndex = url.indexOf("?");
+ String queryPart = quotationMarkIndex > -1 ? url.substring(quotationMarkIndex + 1) : url;
+ String[] paramEntries = queryPart.split("&");
+ for (String paramEntry : paramEntries) {
+ String[] paramEntrySplitted = paramEntry.split("=");
+ if ((paramEntrySplitted.length > 1) && paramName.equalsIgnoreCase(paramEntrySplitted[0])) {
+ oldParamValue = paramEntrySplitted[1];
+
+ return url.replaceFirst(paramName + "=" + oldParamValue, paramName + "=" + newParamValue);
+ }
+ }
+
+ return url;
+ }
+
+}
\ No newline at end of file
Index: lams_bb_integration/src/org/lamsfoundation/ld/integration/blackboard/LamsSecurityUtil.java
===================================================================
diff -u -r46f6e2a2d8c2b6552718747c373df53efd0cfc42 -rb4a4a2a44c27e0307086d3405993f9febe39f13b
--- lams_bb_integration/src/org/lamsfoundation/ld/integration/blackboard/LamsSecurityUtil.java (.../LamsSecurityUtil.java) (revision 46f6e2a2d8c2b6552718747c373df53efd0cfc42)
+++ lams_bb_integration/src/org/lamsfoundation/ld/integration/blackboard/LamsSecurityUtil.java (.../LamsSecurityUtil.java) (revision b4a4a2a44c27e0307086d3405993f9febe39f13b)
@@ -47,6 +47,7 @@
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.lamsfoundation.ld.integration.dto.LearnerProgressDTO;
+import org.lamsfoundation.ld.util.LamsServerException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.xml.sax.SAXException;
@@ -76,6 +77,7 @@
private static Logger logger = Logger.getLogger(LamsSecurityUtil.class);
private static final String DUMMY_COURSE = "Previews";
+ private static final String EXPORT_FOLDER_LAMS_SERVER = "/tmp/lams/";
/**
* Generates login requests to LAMS for author, monitor and learner, using the alternative URL.
@@ -524,23 +526,14 @@
logger.info("LAMS START LESSON Req: " + serviceURL);
- // InputStream is = url.openConnection().getInputStream();
+ // parse xml response and get the lesson id
InputStream is = LamsSecurityUtil.callLamsServerPost(serviceURL);
-
- // parse xml response
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(is);
-
- // get the lesson id from the response
-
- /*
- * The getTextContext is not a java 1.4 method, so Blackboard 7.1 comes up with errors using getNodeValue()
- * instead
- */
- // return Long.parseLong(document.getElementsByTagName("Lesson").item(0).getAttributes().getNamedItem("lessonId").getTextContent());
return Long.parseLong(document.getElementsByTagName("Lesson").item(0).getAttributes()
.getNamedItem("lessonId").getNodeValue());
+
} catch (MalformedURLException e) {
throw new RuntimeException("Unable to start LAMS lesson, bad URL: '" + serverAddr
+ "', please check lams.properties", e);
@@ -593,7 +586,6 @@
try {
String method = "clone";
String timestamp = new Long(System.currentTimeMillis()).toString();
-// String username = "not_available";//signifier for skipping security check as we can't get the current user requested cloning
String hash = generateAuthenticationHash(timestamp, username, serverId);
String serviceURL = serverAddr + "/services/xml/LessonManager?" + "serverId="
+ URLEncoder.encode(serverId, "utf8") + "&datetime=" + timestamp + "&username="
@@ -603,21 +595,14 @@
logger.info("LAMS clone lesson request: " + serviceURL);
+ // parse xml response and get the lesson id
InputStream is = LamsSecurityUtil.callLamsServerPost(serviceURL);
- // parse xml response
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(is);
-
- // get the lesson id from the response
-
- /*
- * The getTextContext is not a java 1.4 method, so Blackboard 7.1 comes up with errors using getNodeValue()
- * instead
- */
- // return Long.parseLong(document.getElementsByTagName("Lesson").item(0).getAttributes().getNamedItem("lessonId").getTextContent());
return Long.parseLong(document.getElementsByTagName("Lesson").item(0).getAttributes()
.getNamedItem("lessonId").getNodeValue());
+
} catch (MalformedURLException e) {
throw new RuntimeException("Unable to clone LAMS lesson, bad URL: '" + serverAddr
+ "', please check lams.properties", e);
@@ -649,6 +634,93 @@
}
/**
+ * Import learning design in LAMS from its temp folder. Then starting a lesson using this learning design.
+ *
+ * @param courseId
+ * courseId as a request parameter
+ * @param ldId
+ * the learning design id for which you wish to start a lesson
+ *
+ * @return lesson id of a cloned lesson
+ * @throws LamsServerException
+ */
+ public static Long importLearningDesign(User teacher, String courseId, String lsId, String ldId) throws LamsServerException {
+
+ String serverId = getServerID();
+ String serverAddr = getServerAddress();
+ String serverKey = getServerKey();
+ String username = teacher.getUserName();
+ String locale = teacher.getLocale();
+ String country = getCountry(locale);
+ String lang = getLanguage(locale);
+
+ if (courseId == null || serverId == null || serverAddr == null || serverKey == null) {
+ logger.info("Unable to import lesson, one or more lams configuration properties or the course id is null");
+ throw new RuntimeException("Unable to import lesson, one or more lams configuration properties or the course id is null. courseId="+courseId);
+ }
+
+ //import a learning design
+ String filePath = EXPORT_FOLDER_LAMS_SERVER + lsId + "_" + ldId + ".zip";
+
+ try {
+ String filePathParam = URLEncoder.encode(filePath, "UTF-8");
+ String timestamp = new Long(System.currentTimeMillis()).toString();
+ String hash = generateAuthenticationHash(timestamp, username, serverId);
+ String serviceURL = serverAddr + "/services/xml/LessonManager?" + "serverId="
+ + URLEncoder.encode(serverId, "utf8") + "&datetime=" + timestamp + "&username="
+ + URLEncoder.encode(username, "utf8") + "&hashValue=" + hash + "&courseId="
+ + URLEncoder.encode(courseId, "UTF8") + "&country="
+ + country + "&lang=" + lang + "&method=import&customCSV=&filePath=" + filePathParam;
+
+ logger.info("LAMS import lesson request: " + serviceURL);
+
+ // parse xml response and get the ldid
+ InputStream is = LamsSecurityUtil.callLamsServerPost(serviceURL);
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document document = db.parse(is);
+ return Long.parseLong(document.getElementsByTagName("Lesson").item(0).getAttributes()
+ .getNamedItem("ldId").getNodeValue());
+
+ } catch (MalformedURLException e) {
+ throw new LamsServerException("Unable to import LAMS lesson, bad URL: '" + serverAddr
+ + "', please check lams.properties. Tried to import file " + filePath, e);
+ } catch (IllegalStateException e) {
+ throw new LamsServerException(
+ "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator. Tried to import file "
+ + filePath,
+ e);
+ } catch (RemoteException e) {
+ throw new LamsServerException(
+ "Unable to import LAMS lesson, RMI Remote Exception. Tried to import file " + filePath, e);
+ } catch (UnsupportedEncodingException e) {
+ throw new LamsServerException(
+ "Unable to import LAMS lesson, Unsupported Encoding Exception. Tried to import file " + filePath,
+ e);
+ } catch (ConnectException e) {
+ throw new LamsServerException(
+ "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator. Tried to import file "
+ + filePath,
+ e);
+ } catch (IOException e) {
+ throw new LamsServerException("Unable to import LAMS lesson. " + e.getMessage()
+ + " Please contact your system administrator. Tried to import file " + filePath, e);
+ } catch (ParserConfigurationException e) {
+ throw new LamsServerException("Unable to import LAMS lesson. " + e.getMessage()
+ + " Can't instantiate DocumentBuilder. Tried to import file " + filePath, e);
+ } catch (SAXException e) {
+ throw new LamsServerException("Unable to import LAMS lesson. " + e.getMessage()
+ + " Can't parse LAMS results. Tried to import file " + filePath, e);
+ } catch (Exception e) {
+ throw new LamsServerException(
+ "Unable to import LAMS lesson. Please contact your system administrator. Tried to import file "
+ + filePath,
+ e);
+ }
+
+ }
+
+ /**
* Pre-adding students and monitors to a lesson
*
* @param ctx
Index: lams_bb_integration/src/org/lamsfoundation/ld/util/LamsServerException.java
===================================================================
diff -u
--- lams_bb_integration/src/org/lamsfoundation/ld/util/LamsServerException.java (revision 0)
+++ lams_bb_integration/src/org/lamsfoundation/ld/util/LamsServerException.java (revision b4a4a2a44c27e0307086d3405993f9febe39f13b)
@@ -0,0 +1,34 @@
+package org.lamsfoundation.ld.util;
+
+/**
+ * Exception that originated at LAMS server.
+ */
+public class LamsServerException extends Exception {
+
+ public LamsServerException() {
+ super();
+ }
+
+ /**
+ * @param message
+ */
+ public LamsServerException(String message) {
+ super(message);
+ }
+
+ /**
+ * @param cause
+ */
+ public LamsServerException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public LamsServerException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
Index: lams_bb_integration/web/links/admin.jsp
===================================================================
diff -u -r46f6e2a2d8c2b6552718747c373df53efd0cfc42 -rb4a4a2a44c27e0307086d3405993f9febe39f13b
--- lams_bb_integration/web/links/admin.jsp (.../admin.jsp) (revision 46f6e2a2d8c2b6552718747c373df53efd0cfc42)
+++ lams_bb_integration/web/links/admin.jsp (.../admin.jsp) (revision b4a4a2a44c27e0307086d3405993f9febe39f13b)
@@ -47,8 +47,13 @@
<%-- Monitor Button --%>
+
+
+
@@ -61,22 +66,7 @@
// Open the LAMS Seuence Monitor Window
function cloneLessons() {
//block #buttons
- $j('#buttons').block({
- message: 'Please, wait. Lessons are getting copied now.
',
- baseZ: 1000000,
- fadeIn: 0,
- css: {
- border: 'none',
- padding: $j('#buttons').height() + 'px',
- backgroundColor: '#000',
- '-webkit-border-radius': '10px',
- '-moz-border-radius': '10px',
- opacity: .98
- },
- overlayCSS: {
- opacity: 0
- }
- });
+ blockButtons();
$j.ajax({
async: true,
@@ -98,6 +88,49 @@
return false;
}
+ function importLessons() {
+ //block #buttons
+ blockButtons();
+
+ $j.ajax({
+ async: true,
+ url: '../ImportLessons',
+ data : 'courseId=<%=ctx.getCourse().getCourseId()%>',
+ type: 'post',
+ success: function (response) {
+ $j("#buttons").unblock();
+ alert(response);
+ },
+ error: function (request, status, error) {
+ $j("#buttons").unblock();
+ alert(error);
+ }
+ });
+
+ return false;
+ }
+
+ //auxiliary method to block #buttons element
+ function blockButtons(){
+
+ $j('#buttons').block({
+ message: 'Please, wait. Lessons are getting copied now.
',
+ baseZ: 1000000,
+ fadeIn: 0,
+ css: {
+ border: 'none',
+ padding: $j('#buttons').height() + 'px',
+ backgroundColor: '#000',
+ '-webkit-border-radius': '10px',
+ '-moz-border-radius': '10px',
+ opacity: .98
+ },
+ overlayCSS: {
+ opacity: 0
+ }
+ });
+ }
+