package edu.asu.spring.quadriga.rest; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.security.Principal; import java.util.Iterator; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.stream.StreamSource; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import org.xml.sax.SAXException; import edu.asu.spring.quadriga.accesschecks.IWSSecurityChecker; import edu.asu.spring.quadriga.aspects.annotations.AccessPolicies; import edu.asu.spring.quadriga.aspects.annotations.CheckedElementType; import edu.asu.spring.quadriga.aspects.annotations.ElementAccessPolicy; import edu.asu.spring.quadriga.aspects.annotations.RestAccessPolicies; import edu.asu.spring.quadriga.domain.IUser; import edu.asu.spring.quadriga.domain.conceptcollection.IConceptCollection; import edu.asu.spring.quadriga.domain.factories.IRestVelocityFactory; import edu.asu.spring.quadriga.domain.factory.conceptcollection.IConceptCollectionFactory; import edu.asu.spring.quadriga.domain.factory.conceptcollection.IConceptFactory; import edu.asu.spring.quadriga.domain.impl.conceptcollection.ConceptCollection; import edu.asu.spring.quadriga.domain.impl.conceptlist.Concept; import edu.asu.spring.quadriga.domain.impl.conceptlist.ConceptList; import edu.asu.spring.quadriga.domain.impl.conceptlist.QuadrigaConceptReply; import edu.asu.spring.quadriga.domain.impl.workspacexml.Workspace; import edu.asu.spring.quadriga.domain.workbench.IProjectConceptCollection; import edu.asu.spring.quadriga.domain.workspace.IWorkspaceConceptCollection; import edu.asu.spring.quadriga.exceptions.QuadrigaAccessException; import edu.asu.spring.quadriga.exceptions.QuadrigaException; import edu.asu.spring.quadriga.exceptions.QuadrigaStorageException; import edu.asu.spring.quadriga.exceptions.RestException; import edu.asu.spring.quadriga.service.IRestMessage; import edu.asu.spring.quadriga.service.IUserManager; import edu.asu.spring.quadriga.service.conceptcollection.IConceptCollectionManager; import edu.asu.spring.quadriga.service.workbench.IProjectConceptCollectionManager; import edu.asu.spring.quadriga.service.workspace.IWorkspaceCCManager; import edu.asu.spring.quadriga.web.login.RoleNames; /** * Controller for conception collection rest apis exposed to other clients * * @author SatyaSwaroop Boddu * @author LohithDwaraka * */ @Controller public class ConceptCollectionRestController { private static final Logger logger = LoggerFactory.getLogger(ConceptCollectionRestController.class); @Autowired private IUserManager usermanager; @Autowired private IRestMessage restMessage; @Autowired private IWorkspaceCCManager workspaceCCManager; @Autowired private IUserManager userManager; @Autowired private IConceptCollectionFactory conceptCollectionFactory; @Autowired private IConceptCollectionManager conceptControllerManager; private IConceptCollection collection; @Autowired private IConceptCollectionFactory collectionFactory; @Autowired private IWSSecurityChecker checkWSSecurity; @Autowired private IConceptFactory conFact; @Autowired private IRestVelocityFactory restVelocityFactory; @Autowired @Qualifier("conceptPowerURL") private String conceptPowerURL; @Autowired @Qualifier("updateConceptPowerURLPath") private String updateConceptPowerURLPath; @Autowired private IProjectConceptCollectionManager projectConceptCollectionManager; /** * Rest interface for the getting list of concept collections of a user * http://<<URL>:<PORT>>/quadriga/rest/conceptcollections * http://localhost:8080/quadriga/rest/conceptcollections * * @param model * ModelMap to handle the requests of client * @param principal * {@link Principal} object to access authenticated user * @param req * {@link HttpServletRequest} object to access request param * @return Produces XML of list of concept collection details * @throws RestException */ @RequestMapping(value = "rest/conceptcollections", method = RequestMethod.GET, produces = "application/xml") public ResponseEntity<String> listConceptCollections(ModelMap model, Principal principal, HttpServletRequest req) throws RestException { try { VelocityEngine engine = restVelocityFactory.getVelocityEngine(); engine.init(); String userId = principal.getName(); List<IConceptCollection> collectionsList = conceptControllerManager.getCollectionsOwnedbyUser(userId); Template template = engine.getTemplate("velocitytemplates/conceptcollections.vm"); VelocityContext context = new VelocityContext(); context.put("url", ServletUriComponentsBuilder.fromContextPath(req).toUriString()); context.put("list", collectionsList); StringWriter writer = new StringWriter(); template.merge(context, writer); return new ResponseEntity<String>(writer.toString(), HttpStatus.OK); } catch (ResourceNotFoundException e) { throw new RestException(404, e); } catch (ParseErrorException e) { throw new RestException(500, e); } catch (MethodInvocationException e) { throw new RestException(500, e); } catch (QuadrigaStorageException e) { throw new RestException(500, e); } catch (Exception e) { throw new RestException(500, e); } } /** * Rest interface to get conceptcollections related to workspace * http://<<URL * >:<PORT>>/quadriga/auth/rest/workspace/{workspaceid}/conceptcollections * .json http://localhost:8080/quadriga/auth/rest/workspace/e23a8585-20bc- * 458e-ab7d-c758962b11aa/conceptcollections.json * * * @author Ajay Modi & Bharath Srikantan * @param workspaceid * @param model * @param principal * @return */ @AccessPolicies({ @ElementAccessPolicy(type = CheckedElementType.WORKSPACE, paramIndex = 1, userRole = { RoleNames.ROLE_WORKSPACE_COLLABORATOR_ADMIN }) }) @RequestMapping(value = "auth/rest/workspace/{workspaceid}/conceptcollections.json", method = RequestMethod.GET, produces = "application/json") @ResponseBody public ResponseEntity<String> listWorkspaceConceptCollection(@PathVariable("workspaceid") String workspaceId, Model model, Principal principal) { String userId = principal.getName(); List<IWorkspaceConceptCollection> conceptCollectionList = null; JSONArray ja = new JSONArray(); try { conceptCollectionList = workspaceCCManager.listWorkspaceCC(workspaceId); } catch (QuadrigaStorageException e) { logger.error("QuadrigaStorageException:", e); return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } if (conceptCollectionList != null) { for (IWorkspaceConceptCollection conceptCollection : conceptCollectionList) { JSONObject j = new JSONObject(); try { j.put("id", conceptCollection.getConceptCollection().getConceptCollectionId()); j.put("name", conceptCollection.getConceptCollection().getConceptCollectionName()); ja.put(j); } catch (JSONException e) { logger.error("JSONException:", e); return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } } } return new ResponseEntity<String>(ja.toString(), HttpStatus.OK); } /** * Rest interface for uploading XML for concept collection * http://<<URL>:<PORT>>/quadriga/rest/syncconcepts/{conceptCollectionID} * http://localhost:8080/quadriga/rest/syncconcepts/ * * @author Lohith Dwaraka * @param request * {@link HttpServletRequest} object to access request URL param * @param response * {@link HttpServletResponse} object to access response and * setting status or/and header details * @param xml * POST data in terms of XML from the client * @param accept * Accepts data of type Application/XML * @return Returns of Application/XML to the client. XML contains concept * which client doesn't have. It helps in syncing the concept at * client and Quadriga. * @throws QuadrigaException * @throws IOException * @throws SAXException * @throws ParserConfigurationException * @throws JAXBException * @throws QuadrigaAccessException * @throws QuadrigaStorageException * @throws RestException */ @RestAccessPolicies({ @ElementAccessPolicy(type = CheckedElementType.CONCEPTCOLLECTION_REST, paramIndex = 1, userRole = { RoleNames.ROLE_CC_COLLABORATOR_ADMIN, RoleNames.ROLE_CC_COLLABORATOR_READ_WRITE }) }) @RequestMapping(value = "rest/syncconcepts/{conceptCollectionID}", method = RequestMethod.POST) public ResponseEntity<String> addConceptsToConceptCollection( @PathVariable("conceptCollectionID") String conceptCollectionId, HttpServletRequest request, HttpServletResponse response, @RequestBody String xml, @RequestHeader("Accept") String accept, Principal principal) throws QuadrigaException, ParserConfigurationException, SAXException, IOException, JAXBException, QuadrigaAccessException, QuadrigaStorageException, RestException { IUser user = userManager.getUser(principal.getName()); if (xml.equals("")) { String errorMsg = restMessage.getErrorMsg("Please provide XML in body of the post request.", request); return new ResponseEntity<String>(errorMsg, HttpStatus.BAD_REQUEST); } logger.debug("XML : " + xml); JAXBElement<QuadrigaConceptReply> response1 = null; try { JAXBContext context = JAXBContext.newInstance(QuadrigaConceptReply.class); Unmarshaller unmarshaller = context.createUnmarshaller(); unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler()); InputStream is = new ByteArrayInputStream(xml.getBytes()); response1 = unmarshaller.unmarshal(new StreamSource(is), QuadrigaConceptReply.class); } catch (JAXBException e) { logger.error("Error in unmarshalling", e); String errorMsg = restMessage.getErrorMsg("Error in unmarshalling", request); return new ResponseEntity<String>(errorMsg, HttpStatus.BAD_REQUEST); } QuadrigaConceptReply qReply = response1.getValue(); ConceptList conList = qReply.getConceptList(); List<Concept> conceptList = conList.getConcepts(); Iterator<Concept> iter = conceptList.iterator(); while (iter.hasNext()) { Concept concept = iter.next(); logger.debug(concept.toString()); try { conceptControllerManager.addItems(concept.getName(), concept.getUri(), concept.getPos(), concept.getDescription(), conceptCollectionId, user.getUserName()); } catch (QuadrigaStorageException e) { logger.error("Errors in adding items", e); String errorMsg = restMessage.getErrorMsg("Failed to add due to DB Error", request); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.valueOf(accept)); return new ResponseEntity<String>(errorMsg, httpHeaders, HttpStatus.INTERNAL_SERVER_ERROR); } } HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.valueOf(accept)); return new ResponseEntity<String>("Success", httpHeaders, HttpStatus.OK); } /** * * Rest interface for the getting list of concept collections of a user * http://<<URL>:<PORT>>/quadriga/rest/workspace/ * <workspaceid>/conceptcollections * http://localhost:8080/quadriga/rest/workspace/WS_22992652874022949/ * conceptcollections * * * @param workspaceId * {@link Workspace} ID , access this parameter to get concept * collection of the {@link Workspace} * @param model * {@link ModelMap} object to access any user request * @param principal * {@link Principal} object to access logged in client. * @param req * {@link HttpServletRequest} object to access the request params * @return Returns the Application/XML of concept collections belongs to * {@link Workspace} * @throws RestException */ @RestAccessPolicies({ @ElementAccessPolicy(type = CheckedElementType.WORKSPACE_REST, paramIndex = 1, userRole = { RoleNames.ROLE_WORKSPACE_COLLABORATOR_ADMIN, RoleNames.ROLE_WORKSPACE_COLLABORATOR_CONTRIBUTOR, RoleNames.ROLE_PROJ_COLLABORATOR_CONTRIBUTOR }) }) @RequestMapping(value = "rest/workspace/{workspaceId}/conceptcollections", method = RequestMethod.GET, produces = "application/xml") public ResponseEntity<String> listWorkspaceConceptCollections(@PathVariable("workspaceId") String workspaceId, ModelMap model, Principal principal, HttpServletRequest req) throws RestException { try { VelocityEngine engine = restVelocityFactory.getVelocityEngine(); engine.init(); String userId = principal.getName(); List<IWorkspaceConceptCollection> collectionsList = workspaceCCManager.listWorkspaceCC(workspaceId); Template template = engine.getTemplate("velocitytemplates/workspaceconceptcollections.vm"); VelocityContext context = new VelocityContext(); context.put("list", collectionsList); context.put("url", ServletUriComponentsBuilder.fromContextPath(req).toUriString()); StringWriter writer = new StringWriter(); template.merge(context, writer); return new ResponseEntity<String>(writer.toString(), HttpStatus.OK); } catch (ResourceNotFoundException e) { throw new RestException(404, e); } catch (ParseErrorException e) { throw new RestException(500, e); } catch (MethodInvocationException e) { throw new RestException(500, e); } catch (QuadrigaStorageException e) { throw new RestException(500, e); } catch (Exception e) { throw new RestException(500, e); } } /** * Rest interface add a new {@link ConceptCollection} to the * {@link Workspace} http://<<URL>:<PORT>>/quadriga/rest/workspace/ * <workspaceid>/createcc * http://localhost:8080/quadriga/rest/workspace/WS_22992652874022949/ * createcc * * @param workspaceId * {@link Workspace} ID , access this parameter to get concept * collection of the {@link Workspace} * @param request * {@link HttpServletRequest} object to access the request params * @param response * {@link HttpServletResponse} object to access response and * setting status or/and header details * @param xml * POST data in terms of XML from the client * @param accept * Accepts data of type Application/XML * @param model * {@link ModelMap} object to access any user request * @param principal * {@link Principal} object to access logged in client. * @return Response of XML of success in creating the concept collection in * the workspace. * @throws RestException * @throws QuadrigaStorageException * @throws QuadrigaAccessException */ @RestAccessPolicies({ @ElementAccessPolicy(type = CheckedElementType.WORKSPACE_REST, paramIndex = 1, userRole = { RoleNames.ROLE_WORKSPACE_COLLABORATOR_ADMIN, RoleNames.ROLE_WORKSPACE_COLLABORATOR_CONTRIBUTOR }) }) @RequestMapping(value = "rest/workspace/{workspaceId}/createcc", method = RequestMethod.POST) public ResponseEntity<String> addConceptCollectionsToWorkspace(@PathVariable("workspaceId") String workspaceId, HttpServletRequest request, HttpServletResponse response, @RequestBody String xml, @RequestHeader("Accept") String accept, ModelMap model, Principal principal) throws RestException, QuadrigaStorageException, QuadrigaAccessException { IUser user = usermanager.getUser(principal.getName()); String ccName = request.getParameter("name"); String desc = request.getParameter("desc"); if (!checkWSSecurity.checkIsWorkspaceExists(workspaceId)) { String errorMsg = restMessage.getErrorMsg("Workspace ID : " + workspaceId + " doesn't exist", request); return new ResponseEntity<String>(errorMsg, HttpStatus.NOT_FOUND); } if (ccName == null || ccName.isEmpty()) { String errorMsg = restMessage.getErrorMsg("Please provide concept collection name", request); return new ResponseEntity<String>(errorMsg, HttpStatus.BAD_REQUEST); } if (desc == null || desc.isEmpty()) { String errorMsg = restMessage.getErrorMsg("Please provide concept collection description", request); return new ResponseEntity<String>(errorMsg, HttpStatus.BAD_REQUEST); } logger.debug("XML : " + xml); JAXBElement<QuadrigaConceptReply> response1 = null; try { JAXBContext context = JAXBContext.newInstance(QuadrigaConceptReply.class); Unmarshaller unmarshaller = context.createUnmarshaller(); unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler()); InputStream is = new ByteArrayInputStream(xml.getBytes()); response1 = unmarshaller.unmarshal(new StreamSource(is), QuadrigaConceptReply.class); } catch (JAXBException e) { logger.error("Error in unmarshalling", e); String errorMsg = restMessage.getErrorMsg("Error in unmarshalling", request); return new ResponseEntity<String>(errorMsg, HttpStatus.BAD_REQUEST); } QuadrigaConceptReply qReply = response1.getValue(); ConceptList conList = qReply.getConceptList(); List<Concept> conceptList = conList.getConcepts(); if (conceptList.size() < 1) { String errorMsg = restMessage.getErrorMsg("Concepts XML is not valid", request); return new ResponseEntity<String>(errorMsg, HttpStatus.BAD_REQUEST); } IConceptCollection collection = conceptCollectionFactory.createConceptCollectionObject(); collection.setDescription(desc); collection.setOwner(user); collection.setConceptCollectionName(ccName); conceptControllerManager.addConceptCollection(collection); String ccId = collection.getConceptCollectionId(); Iterator<Concept> iter = conceptList.iterator(); while (iter.hasNext()) { Concept concept = iter.next(); logger.debug(concept.toString()); try { conceptControllerManager.addItems(concept.getName().trim(), concept.getUri().trim(), concept.getPos() .trim(), concept.getDescription().trim(), ccId, user.getUserName()); } catch (QuadrigaStorageException e) { logger.error("Errors in adding items", e); String errorMsg = restMessage.getErrorMsg("Failed to add due to DB Error", request); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.valueOf(accept)); return new ResponseEntity<String>(errorMsg, httpHeaders, HttpStatus.INTERNAL_SERVER_ERROR); } } workspaceCCManager.addWorkspaceCC(workspaceId, ccId, user.getUserName()); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.valueOf(accept)); return new ResponseEntity<String>(ccId, httpHeaders, HttpStatus.OK); } /** * Rest interface for the getting concept details i.e, list of items in the * collection http://<<URL>: * <PORT>>/quadriga/rest/conceptdetails/{collectionID} * http://localhost:8080/quadriga/rest/conceptdetails/167 * * @author SatyaSwaroop Boddu * @param collectionID * {@link ConceptCollection} ID to access the object details from * the DB * @param model * {@link ModelMap} object to access any user request * @return Response would be the XML containing the concepts belonging to * {@link ConceptCollection} ID. * @throws RestException * @throws Exception */ @RequestMapping(value = "rest/conceptdetails/{collectionID}", method = RequestMethod.GET, produces = "application/xml") public ResponseEntity<String> getConceptList(@PathVariable("collectionID") String collectionID, ModelMap model, HttpServletRequest req, Principal principal) throws RestException { StringWriter sw = new StringWriter(); IConceptCollection collection; try { collection = conceptControllerManager.getConceptCollection(collectionID); } catch (QuadrigaStorageException e1) { throw new RestException(500, e1); } collection.setConceptCollectionId(collectionID); try { VelocityEngine engine = restVelocityFactory.getVelocityEngine(); engine.init(); Template template = engine.getTemplate("velocitytemplates/conceptdetails.vm"); VelocityContext context = new VelocityContext(); context.put("list", collection.getConceptCollectionConcepts()); context.put("conceptPowerURL", conceptPowerURL); context.put("path", updateConceptPowerURLPath); context.put("url", ServletUriComponentsBuilder.fromContextPath(req).toUriString()); template.merge(context, sw); return new ResponseEntity<String>(sw.toString(), HttpStatus.OK); } catch (ResourceNotFoundException e) { throw new RestException(404, e); } catch (ParseErrorException e) { throw new RestException(500, e); } catch (MethodInvocationException e) { throw new RestException(500, e); } catch (QuadrigaStorageException e) { throw new RestException(500, e); } catch (QuadrigaAccessException e) { throw new RestException(403, e); } catch (Exception e) { throw new RestException(500, e); } } /** * Rest interface to get conceptcollections related to project * http://<<URL>: * <PORT>>/quadriga/auth/rest/<projectid>/conceptcollections.json * http://localhost * :8080/quadriga/auth/rest/PROJ_bb7ad41b-3e85-4309-b2ff-47d644307 * b9b/conceptcollections.json * * * @author Ajay Modi & Bharath Srikantan * @param projectid * @param model * @param principal * @return */ @RequestMapping(value = "auth/rest/{projectid}/conceptcollections.json", method = RequestMethod.GET, produces = "application/json") public ResponseEntity<String> listProjectConceptCollectionJson(@PathVariable("projectid") String projectid, Model model, Principal principal) { String userId = principal.getName(); List<IProjectConceptCollection> projectConceptCollectionList = null; // TODO: listProjectConceptCollection() needs to be modified try { projectConceptCollectionList = projectConceptCollectionManager.listProjectConceptCollection(projectid); } catch (QuadrigaStorageException e) { logger.error("QuadrigaStorageException:", e); return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } JSONArray ja = new JSONArray(); if (projectConceptCollectionList != null) { for (IProjectConceptCollection conceptCollection : projectConceptCollectionList) { JSONObject j = new JSONObject(); try { j.put("id", conceptCollection.getConceptCollection().getConceptCollectionId()); j.put("name", conceptCollection.getConceptCollection().getConceptCollectionName()); ja.put(j); } catch (JSONException e) { logger.error("JSONException:", e); return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } } } return new ResponseEntity<String>(ja.toString(), HttpStatus.OK); } }