LearnPAd/learnpad

View on GitHub
lp-ontology-recommender/src/main/java/eu/learnpad/or/impl/OntologyRecommenderImpl.java

Summary

Maintainability
D
1 day
Test Coverage
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package eu.learnpad.or.impl;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.inject.Named;
import javax.inject.Singleton;
import javax.ws.rs.Path;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;

import org.xwiki.component.annotation.Component;
import org.xwiki.component.phase.Initializable;
import org.xwiki.component.phase.InitializationException;

import eu.learnpad.core.impl.or.XwikiBridge;
import eu.learnpad.core.impl.or.XwikiCoreFacadeRestResource;
import eu.learnpad.dash.rest.data.KPIValuesFormat;
import eu.learnpad.exception.LpRestException;
import eu.learnpad.exception.impl.LpRestExceptionXWikiImpl;
import eu.learnpad.me.rest.data.KPIsFormat;
import eu.learnpad.me.rest.data.ModelSetType;
import eu.learnpad.ontology.config.APP;
import eu.learnpad.ontology.analyzer.Analyzer;
import eu.learnpad.ontology.kpi.KBProcessorNotifier;
import eu.learnpad.ontology.kpi.dashboard.KPILoader;
import eu.learnpad.ontology.persistence.FileOntAO;
import eu.learnpad.ontology.wiki.UserActionNotificationLog;
import eu.learnpad.ontology.recommender.Recommender;
import eu.learnpad.ontology.recommender.RecommenderException;
import eu.learnpad.ontology.recommender.cbr.CBRAdapter;
import eu.learnpad.ontology.simulation.SimulationScoreLog;
import eu.learnpad.ontology.transformation.SimpleModelTransformator;
import eu.learnpad.or.rest.data.BusinessActor;
import eu.learnpad.or.rest.data.Entities;
import eu.learnpad.or.rest.data.Entity;
import eu.learnpad.or.rest.data.Experts;
import eu.learnpad.or.rest.data.LearningMaterial;
import eu.learnpad.or.rest.data.LearningMaterials;
import eu.learnpad.or.rest.data.NotificationActionType;
import eu.learnpad.or.rest.data.OrganisationalUnit;
import eu.learnpad.or.rest.data.Recommendations;
import eu.learnpad.or.rest.data.RelatedObject;
import eu.learnpad.or.rest.data.RelatedObjects;
import eu.learnpad.or.rest.data.ResourceType;
import eu.learnpad.or.rest.data.SimulationData;
import eu.learnpad.or.rest.data.SimulationScoresMap;
import eu.learnpad.or.rest.data.States;
import eu.learnpad.or.rest.data.kbprocessing.KBProcessId;
import eu.learnpad.or.rest.data.kbprocessing.KBProcessingStatus;
import eu.learnpad.or.rest.data.kbprocessing.KBProcessingStatusType;
import eu.learnpad.or.rest.data.kbprocessing.KBProcessingStatus.Info;
import eu.learnpad.sim.rest.event.ScoreType;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 *
 * @author sandro.emmenegger
 */
@Component
@Singleton
@Named("eu.learnpad.or.impl.OntologyRecommenderImpl")
@Path("/learnpad/or/bridge")
public class OntologyRecommenderImpl extends XwikiBridge implements Initializable, KBProcessorNotifier {

    private Map<String, KBProcessingStatusType> kbProcessingStatusMap;

    
    @Override
    public void initialize() throws InitializationException {
        this.corefacade = new XwikiCoreFacadeRestResource();
        this.kbProcessingStatusMap = Collections.synchronizedMap(new HashMap<String, KBProcessingStatusType>());

        SimpleModelTransformator.getInstance();        
    }

    @Override
    public void modelSetImported(String modelSetId, ModelSetType type) throws LpRestException {
        InputStream modelSetInputStream = this.corefacade.getModel(modelSetId, type);
        if (modelSetInputStream == null) {
            throw new LpRestExceptionXWikiImpl("Modelset for id '" + modelSetId + "' and type '" + type + "' not found!");
        }
        SimpleModelTransformator.getInstance().transform(modelSetId, this.corefacade.getModel(modelSetId, type), type);
        
        //reload models of new/changed modelset
        try {
            FileOntAO.getInstance().reload(modelSetId);
        } catch (RecommenderException ex) {
           Logger.getLogger(OntologyRecommenderImpl.class.getName()).log(Level.SEVERE, null, ex);
           throw new LpRestExceptionXWikiImpl("Modelset import and ontology reload failed. ", ex);
        }
    }

    @Override
    public void kpisImported(String modelSetId, String kpisId, KPIsFormat type)
            throws LpRestException {
        InputStream kpisInputStream = this.corefacade.getExternalKPIs(modelSetId, kpisId, type);
        if (kpisInputStream == null) {
            throw new LpRestExceptionXWikiImpl("KPIs for id '"+ kpisId +"' and type '" + type + "' in ModelSet '"+ modelSetId +"' not found!");
        }
        try {        
            String kpiFileName = APP.CONF.getString("working.directory") + "/" + APP.CONF.getString("kpi.dashboard.data.folder.relative") + "/" + kpisId + "." + type.toString().toLowerCase();
            java.nio.file.Path destination = Paths.get(kpiFileName);
            Files.copy(kpisInputStream, destination,StandardCopyOption.REPLACE_EXISTING);
        } catch ( IOException e) {
            throw new LpRestExceptionXWikiImpl(e.getMessage(),e.getCause());
        }

    }
        
    @Override
    public void resourceNotification(String modelSetId, String modelId, String artifactId, String resourceId, ResourceType resourceType, String userId, Long timestamp, NotificationActionType action) throws LpRestException {
        try {
            UserActionNotificationLog.getInstance().logResourceNotification(modelSetId, modelId, artifactId, resourceId, resourceType, userId, timestamp, action);
        } catch (RecommenderException ex) {
            Logger.getLogger(OntologyRecommenderImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new LpRestExceptionXWikiImpl("Loging resource notification failed. ", ex);
        }
    }

    @Override
    public Recommendations askRecommendation(String modelSetId,
            String artifactId, String userId, String simulationSessionId) throws LpRestException {

        try {
            Recommendations rec = Recommender.getInstance().getRecommendations(modelSetId, artifactId, userId, simulationSessionId);
            return rec;
        } catch (Exception ex) {
            Logger.getLogger(OntologyRecommenderImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new LpRestExceptionXWikiImpl("Asking for recommendations failed with parameters: "
                    + "modelsetId='" + modelSetId
                    + "' artifactId='" + artifactId
                    + "' userId='" + userId
                    + "' simulationSessionId='" + simulationSessionId + "'. ", ex);
        }
    }

    @Override
    public void simulationInstanceNotification(String modelSetId, String modelId, String action, String simulationId, SimulationData data) throws LpRestException {
        // This modification is done because currently the ontology does not deals with
        // data submitted by the user during simulation, but only with session data.
        // In future when the ontology will support this, the following line should be removed        
        data.setSubmittedData(new HashMap<String, Object>());
        CBRAdapter.getInstance().createOrUpdateSimulationSessionCase(simulationId, data);
    }

    @Override
    public void simulationTaskStartNotification(String modelSetId, String modelId, String artifactId, String simulationId, SimulationData data) throws LpRestException {
        // This modification is done because currently the ontology does not deals with
        // data submitted by the user during simulation, but only with session data.
        // In future when the ontology will support this, the following line should be removed        
        data.setSubmittedData(new HashMap<String, Object>());
        CBRAdapter.getInstance().createOrUpdateSimulationSessionCase(simulationId, data);
    }

    @Override
    public void simulationTaskEndNotification(String modelSetId, String modelId, String artifactId, String simulationId, SimulationData data) throws LpRestException {
        // This modification is done because currently the ontology does not deals with
        // data submitted by the user during simulation, but only with session data.
        // In future when the ontology will support this, the following line should be removed        
        data.setSubmittedData(new HashMap<String, Object>());
        CBRAdapter.getInstance().createOrUpdateSimulationSessionCase(simulationId, data);
    }

    @Override
    public void addExecutionState(String modelSetId, String executionId, String userId, String threadId, String pageId, String artifactId) throws LpRestException {
        // TODO Postponed
    }

    @Override
    public States listExecutionStates(String userId) throws LpRestException {
//        States states = ExecutionStates.getInstance().getStatesOfLatestAddedModelSet(userId);
//        return states;
        return null; //not used up to now
    }

    @Override
    public Entities analyseText(String modelSetId, String contextArtifactId, String userId, String title, String text) throws LpRestException {

        Entities entities = new Entities();
        
        Analyzer textAnalyzer = Analyzer.getInstance();
            try {
                entities = textAnalyzer.analyze(modelSetId, text);
            } catch (RecommenderException ex) {
                Logger.getLogger(OntologyRecommenderImpl.class.getName()).log(Level.SEVERE, "Text analysis failed. ", ex);
            }
        return entities;
        
//        return this.generateFakeAnswerForAnalyseText(modelSetId, text);
    }

    private Entities generateFakeAnswerForAnalyseText(String modelSetId, String text) {
        Entities fakeData = new Entities();

        String id = UUID.randomUUID().toString();

        //For testing purposes only !
        String analysedText = text;
        if(text.contains("Sally Shugar")){
            analysedText = analysedText.replace("Sally Shugar", "<span data-recommendation=\"" + id + "\">Sally Shugar</span>");
        }
        
        fakeData.setAnalyzedContent(analysedText);

        Entity entity = new Entity();
        entity.setId(id);
        entity.setModelSetId(modelSetId);
        entity.setModelId("mod.39886");
        entity.setObjectId("obj.39926");
        entity.setContextArtifactId("transfer:obj.35315");
        entity.setType("eo:Person");
        BusinessActor person = new BusinessActor();
        person.setUri("transfer:obj.34872");
        person.setName("Sally Shugar");
        person.setEmail("s.shugar@learnpad.eu");
        person.setSkypeId("learnpad_sally");
        person.setPhoneNumber("+234 23223 123");
        person.setOfficeAddress("Yellow drive 244b, East Juhee, Malta");
        person.setRole("Responsible SUAP Officer");
        OrganisationalUnit orgUnit = new OrganisationalUnit();
        orgUnit.setName("SUAP Office");
        orgUnit.setUri("transfer:obj.122121");
        person.setOrganisationalUnit(orgUnit);
        entity.setPerson(person);

        //related objects
        List<RelatedObject> listOfRelatedObjects = new ArrayList<>();
        RelatedObject relatedObject1 = new RelatedObject();
        relatedObject1.setRelationType("sameCreator");
        relatedObject1.setName("Management ABC for public administrations");
        relatedObject1.setDescription("This self study book with learning material is the definitve guide to manage a team in public administration.");
        relatedObject1.setDocumentUrl("http://learnpad.eu/material/PublicAdministrationABC.pdf");
        relatedObject1.setMimeType("application/pdf");
        relatedObject1.setUri("transfer:obj.21321");
        listOfRelatedObjects.add(relatedObject1);

        RelatedObject relatedObject2 = new RelatedObject();
        relatedObject1.setRelationType("sameAuthor");
        relatedObject2.setName("Best practices for organizing a service conference");
        relatedObject2.setDescription("A set of best practices with many hints for organizing a service conference.");
        relatedObject2.setDocumentUrl("http://learnpad.eu/material/BestPracticesServiceConferenceOrganisatoin.pdf");
        relatedObject2.setMimeType("application/pdf");
        relatedObject2.setUri("transfer:obj.21322");
        listOfRelatedObjects.add(relatedObject2);
        RelatedObjects relatedObjects = new RelatedObjects();
        relatedObjects.setRelatedObjects(listOfRelatedObjects);

        entity.setRelatedObjects(relatedObjects);
        List<Entity> entities = new ArrayList<>();
        entities.add(entity);
        fakeData.setEntities(entities);
        return fakeData;
    }

    @Override
    public void createBookmark(String modelSetId, String userId, String artifactId, String contextArtifactId) throws LpRestException {
        //TODO
    }

    @Override
    public Recommendations getAllBookmarks(String modelSetId, String userId, String artifactId) throws LpRestException {

        Recommendations testData = new Recommendations();

        BusinessActor person = new BusinessActor();
        person.setName("Sally Shugar");
        person.setEmail("s.shugar@learnpad.eu");
        person.setPhoneNumber("+234 23223 123");
        person.setSkypeId("learnpad_sally");
        person.setOfficeAddress("Yellow drive 244b, East Juhee, Malta");
        person.setRole("Responsible SUAP Officer");
        person.setUri("lpd:Sally_Shugar");
        OrganisationalUnit orgUnit = new OrganisationalUnit();
        orgUnit.setName("SUAP Office");
        orgUnit.setUri("obj.122121");
        person.setOrganisationalUnit(orgUnit);
        List<BusinessActor> expertList = new ArrayList();
        expertList.add(person);
        Experts experts = new Experts();
        experts.setBusinessActors(expertList);
        testData.setExperts(experts);

        LearningMaterial learningMaterial = new LearningMaterial();
        learningMaterial.setName("Management ABC for public administrations");
        learningMaterial.setDescription("This self study book with learning material is the definitve guide to manage a team in public administration.");
        learningMaterial.setUrl("http://learnpad.eu/material/PublicAdministrationABC.pdf");
        learningMaterial.setMimeType("application/pdf");
        learningMaterial.setId("transfer:obj.21321");

        List<LearningMaterial> learningMaterialsList = new ArrayList<>();
        learningMaterialsList.add(learningMaterial);
        LearningMaterials materials = new LearningMaterials();
        materials.setLearningMaterials(learningMaterialsList);
        testData.setLearningMaterials(materials);

        return testData;
    }

    @Override
    public KBProcessId calculateKPI(String modelSetId) throws LpRestException {

        Logger.getLogger(OntologyRecommenderImpl.class.getName()).log(Level.INFO, "Inside " + this.getClass().getCanonicalName() + ".calculateKPI");
            
        KPILoader kpiLoader = new KPILoader(this, modelSetId);
        
        String kbProcessId = kpiLoader.getKPILoaderID();         
        if (this.kbProcessingStatusMap.containsKey(kbProcessId)){
            LpRestException e = new LpRestExceptionXWikiImpl("Duplicated KBProcessId, current implementation does not deal properly with multithread accessing kbProcessingStatusMap in "+ this.getClass().getCanonicalName());
            throw e;
        }            
        
        KBProcessId out = new KBProcessId();
        out.setId(kbProcessId);
        this.kbProcessingStatusMap.put(kbProcessId, KBProcessingStatusType.NEVER_STARTED);
        
        kpiLoader.start();

        return out;
    }

    @Override
    public KBProcessingStatus getHandlingProcessStatus(String kbProcessId)
            throws LpRestException {
        Logger.getLogger(OntologyRecommenderImpl.class.getName()).log(Level.INFO, "Inside " + this.getClass().getCanonicalName() + ".getHandlingProcessStatus");
        KBProcessingStatus out = new KBProcessingStatus();
        
        KBProcessingStatusType status = KBProcessingStatusType.NEVER_STARTED; 
        if (this.kbProcessingStatusMap.containsKey(kbProcessId)){
            status = this.kbProcessingStatusMap.get(kbProcessId);
        }    
        
        out.setStatus(status);

        return out;
    }

    private KBProcessingStatus fakeKBProcessingStatus() {
        KBProcessingStatus fake = new KBProcessingStatus();
        fake.setStatus(KBProcessingStatusType.IN_PROGRESS);

        Info info = new Info();
        JAXBElement<String> jaxbElement
                = new JAXBElement(new QName("InfoContentTag"),
                        String.class, "this-status-is-fake");
        info.getAny().add(jaxbElement);
        return fake;
    }

    @Override
    public void notifyProcessingStatus(String kbProcessId, KBProcessingStatusType status) {
            this.kbProcessingStatusMap.put(kbProcessId, status);
    }

    @Override
    public void notifyKPIValues(String modelSetId, KPIValuesFormat format,
                    String businessActorId, InputStream cockpitContent) throws LpRestException {
            try {
                    this.corefacade.pushKPIValues(modelSetId, format, businessActorId, cockpitContent);
            } catch (LpRestException e) {
                    Logger.getLogger(OntologyRecommenderImpl.class.getName()).log(Level.WARNING,"Exception:" + e.getMessage());
                    throw e;
            }
    }

    @Override
    public void updateSimulationScore(String modelSetId, String simulationSessionId, String processArtifactId, Long timestamp, String userId, SimulationScoresMap scoreMap) throws LpRestException {
        Map<ScoreType, Float> scores = scoreMap.getScoreMap();
      
        try {
            SimulationScoreLog.getInstance().logSimulationScore(timestamp, simulationSessionId, modelSetId, processArtifactId, userId, scores);
        } catch (RecommenderException ex) {
            Logger.getLogger(OntologyRecommenderImpl.class.getName()).log(Level.WARNING, "Cannot update simulation score.", ex);
            String mapAsAString = "";
            if (scores.isEmpty()){
                    mapAsAString = "--no_elements_in_the_map--";
            }else{
                for (ScoreType type : scores.keySet()) {
                    mapAsAString += type.name() + "--->" + scores.get(type) + ";";
                }
            }
            throw new LpRestExceptionXWikiImpl("Simulation score update failed: "
                + "modelsetId='" + modelSetId
                + "' simulationSessionId='" + String.valueOf(simulationSessionId)
                + "' processArtifactId='" + String.valueOf(processArtifactId)
                + "' timestamp='" + String.valueOf(timestamp)                        
                + "' userId='" + userId
                + "' scoreMap=[" + mapAsAString + "]. ", ex);
        }
    }

}