You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by dg...@apache.org on 2021/03/31 10:32:55 UTC

[unomi] branch UNOMI-449-forward-public-endpoints created (now 794176b)

This is an automated email from the ASF dual-hosted git repository.

dgriffon pushed a change to branch UNOMI-449-forward-public-endpoints
in repository https://gitbox.apache.org/repos/asf/unomi.git.


      at 794176b  UNOMI-449 : forward existing endpoints to jax-rs endpoints

This branch includes the following new commits:

     new 794176b  UNOMI-449 : forward existing endpoints to jax-rs endpoints

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[unomi] 01/01: UNOMI-449 : forward existing endpoints to jax-rs endpoints

Posted by dg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dgriffon pushed a commit to branch UNOMI-449-forward-public-endpoints
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit 794176bad4faa54eab1a30d58937aeee9f40c19b
Author: David Griffon <dg...@jahia.com>
AuthorDate: Wed Mar 31 12:32:32 2021 +0200

    UNOMI-449 : forward existing endpoints to jax-rs endpoints
---
 .../java/org/apache/unomi/rest/ClientEndpoint.java | 50 +++++++-----
 .../org/apache/unomi/rest/ContextJsonEndpoint.java | 91 +++++++++-------------
 .../apache/unomi/rest/EventsCollectorEndpoint.java | 56 ++++++-------
 3 files changed, 88 insertions(+), 109 deletions(-)

diff --git a/rest/src/main/java/org/apache/unomi/rest/ClientEndpoint.java b/rest/src/main/java/org/apache/unomi/rest/ClientEndpoint.java
index fb7f046..6d0f689 100644
--- a/rest/src/main/java/org/apache/unomi/rest/ClientEndpoint.java
+++ b/rest/src/main/java/org/apache/unomi/rest/ClientEndpoint.java
@@ -25,7 +25,6 @@ import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
 import org.apache.unomi.api.Profile;
 import org.apache.unomi.api.services.ConfigSharingService;
 import org.apache.unomi.api.services.ProfileService;
-import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
@@ -37,9 +36,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.io.OutputStream;
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -51,8 +48,6 @@ import java.util.Set;
  * A servlet filter to serve a context-specific Javascript containing the current request context object.
  */
 @WebService
-@Produces
-@Consumes(MediaType.TEXT_PLAIN)
 @CrossOriginResourceSharing(
         allowAllOrigins = true,
         allowCredentials = true
@@ -62,30 +57,40 @@ import java.util.Set;
 public class ClientEndpoint {
 
     private static final Logger logger = LoggerFactory.getLogger(ClientEndpoint.class.getName());
-    private static final long serialVersionUID = 2928875960103325238L;
+    private static final String CONTENT_DISPOSITION_HEADER_KEY = "Content-Disposition";
+
+    private static final String FILE_NAME_WO_EXT = "my-profile";
+
+    private static String getContentDispostionHeader(String extension) {
+        return String.format("attachment; filename=\"%s.%s\"", FILE_NAME_WO_EXT, extension);
+    }
 
     @Reference
     private ProfileService profileService;
     @Reference
     private ConfigSharingService configSharingService;
 
-    private final String FILE_NAME_WO_EXT = "my-profile";
 
     @Context
     HttpServletRequest request;
     @Context
     HttpServletResponse response;
 
+    @OPTIONS
+    @Path("/client/{operation}/{param}")
+    public Response options() {
+        return Response.status(Response.Status.NO_CONTENT).build();
+    }
+
     @GET
     @Path("/client/{operation}/{param}")
     public Response getClient(@PathParam("operation") String operation, @PathParam("param") String param) throws JsonProcessingException {
-        switch (operation) {
-            case "myprofile":
-                if (((String) configSharingService.getProperty("allowedProfileDownloadFormats")).contains(param)) {
-                    return donwloadCurrentProfile(param);
-                } else {
-                    throw new InternalServerErrorException(String.format("%s is not an allowed param", param));
-                }
+        if ("myprofile".equals(operation)) {
+            if (((String) configSharingService.getProperty("allowedProfileDownloadFormats")).contains(param)) {
+                return donwloadCurrentProfile(param);
+            } else {
+                throw new InternalServerErrorException(String.format("%s is not an allowed param", param));
+            }
         }
         throw new NotFoundException();
     }
@@ -112,8 +117,9 @@ public class ClientEndpoint {
                         return prepareCsvFileToDownload(currentProfile, request.getParameter("vertical") != null);
                     case "text":
                         return prepareYamlFileToDownload(currentProfile, true);
+                    default:
+                        throw new NotFoundException();
                 }
-
             }
         }
         throw new NotFoundException();
@@ -121,7 +127,8 @@ public class ClientEndpoint {
 
     private Response prepareCsvFileToDownload(Profile currentProfile, boolean vertical) {
         response.setContentType("text/csv");
-        response.setHeader("Content-Disposition", "attachment; filename=\"" + FILE_NAME_WO_EXT + ".csv\"");
+
+        response.setHeader(CONTENT_DISPOSITION_HEADER_KEY, getContentDispostionHeader("csv"));
         StringWriter writer = new StringWriter();
         //using custom delimiter and quote character
         CSVWriter csvWriter = new CSVWriter(writer);
@@ -132,12 +139,12 @@ public class ClientEndpoint {
             }
         } else {
             Set<String> keySet = currentProfile.getProperties().keySet();
-            List<String> values = new ArrayList();
+            List<String> values = new ArrayList<>();
             for (Object value : currentProfile.getProperties().values()) {
                 values.add(value.toString().trim().replace("\n", ""));
             }
-            csvWriter.writeNext(keySet.toArray(new String[keySet.size()]));
-            csvWriter.writeNext(values.toArray(new String[values.size()]));
+            csvWriter.writeNext(keySet.toArray(new String[0]));
+            csvWriter.writeNext(values.toArray(new String[0]));
         }
         Response.ResponseBuilder responseBuilder = Response.ok(writer.toString());
         return responseBuilder.build();
@@ -145,7 +152,8 @@ public class ClientEndpoint {
 
     private Response prepareJsonFileToDownload(Profile currentProfile) throws JsonProcessingException {
         response.setContentType("text/json");
-        response.setHeader("Content-Disposition", "attachment; filename=\"" + FILE_NAME_WO_EXT + ".json\"");
+        response.setHeader(CONTENT_DISPOSITION_HEADER_KEY, getContentDispostionHeader("json"));
+
         ObjectMapper mapper = new ObjectMapper();
         String jsonContent = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(currentProfile.getProperties());
         return Response.ok(jsonContent).build();
@@ -153,7 +161,7 @@ public class ClientEndpoint {
 
     private Response prepareYamlFileToDownload(Profile currentProfile, boolean asTextFile) throws JsonProcessingException {
         response.setContentType("text/" + (asTextFile ? "plain" : "yaml"));
-        response.setHeader("Content-Disposition", "attachment; filename=\"" + FILE_NAME_WO_EXT + (asTextFile ? ".txt" : ".yml") + "\"");
+        response.setHeader(CONTENT_DISPOSITION_HEADER_KEY, getContentDispostionHeader((asTextFile ? "txt" : "yml")));
         YAMLFactory yf = new YAMLFactory();
         ObjectMapper mapper = new ObjectMapper(yf);
         String yamlContent = mapper.writeValueAsString(currentProfile.getProperties());
diff --git a/rest/src/main/java/org/apache/unomi/rest/ContextJsonEndpoint.java b/rest/src/main/java/org/apache/unomi/rest/ContextJsonEndpoint.java
index 9a205ca..26e787c 100644
--- a/rest/src/main/java/org/apache/unomi/rest/ContextJsonEndpoint.java
+++ b/rest/src/main/java/org/apache/unomi/rest/ContextJsonEndpoint.java
@@ -17,15 +17,11 @@
 
 package org.apache.unomi.rest;
 
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.cxf.jaxrs.utils.ExceptionUtils;
 import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
 import org.apache.unomi.api.*;
 import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.services.*;
-import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.utils.Changes;
 import org.apache.unomi.utils.HttpUtils;
 import org.apache.unomi.utils.ServletCommon;
@@ -48,7 +44,7 @@ import java.util.*;
 
 @WebService
 @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
-@Consumes(MediaType.TEXT_PLAIN)
+@Consumes(MediaType.APPLICATION_JSON)
 @CrossOriginResourceSharing(
         allowAllOrigins = true,
         allowCredentials = true
@@ -82,9 +78,22 @@ public class ContextJsonEndpoint {
     @Reference
     private ConfigSharingService configSharingService;
 
+    @OPTIONS
+    @Path("/context.json")
+    public Response options() {
+        return Response.status(Response.Status.NO_CONTENT).header("Access-Control-Allow-Origin", "*").build();
+    }
+
     @POST
     @Path("/context.json")
-    public ContextResponse getContextJSON(String contextRequestAsString, @QueryParam("timestamp") Long timestampAsLong, @CookieParam("context-profile-id") String cookieProfileId) {
+    public ContextResponse getContextJSON(
+            ContextRequest contextRequest,
+            @QueryParam("personaId") String personaId,
+            @QueryParam("sessionId") String sessionId,
+            @QueryParam("timestamp") Long timestampAsLong,
+            @QueryParam("invalidateProfile") boolean invalidateProfile,
+            @QueryParam("invalidateSession") boolean invalidateSession
+    ) {
         Date timestamp = new Date();
         if (timestampAsLong != null) {
             timestamp = new Date(timestampAsLong);
@@ -93,7 +102,6 @@ public class ContextJsonEndpoint {
         // Handle persona
         Profile profile = null;
         Session session = null;
-        String personaId = request.getParameter("personaId");
         if (personaId != null) {
             PersonaWithSessions personaWithSessions = profileService.loadPersonaWithSessions(personaId);
             if (personaWithSessions == null) {
@@ -105,32 +113,16 @@ public class ContextJsonEndpoint {
             }
         }
 
-        // Extract payload
-        ContextRequest contextRequest = null;
         String scope = null;
-        String sessionId = null;
-        String profileId = null;
-        ObjectMapper mapper = CustomObjectMapper.getObjectMapper();
-        JsonFactory factory = mapper.getFactory();
-        try {
-            contextRequest = mapper.readValue(factory.createParser(contextRequestAsString), ContextRequest.class);
-        } catch (Exception e) {
-            logger.error("Cannot deserialize the context request payload. See debug level for more information");
-            if (logger.isDebugEnabled()) {
-                logger.debug("Cannot deserialize the context request payload because of {}", e.getMessage(), e);
-            }
-            throw ExceptionUtils.toHttpException(e, null);
-        }
         if (contextRequest.getSource() != null) {
             scope = contextRequest.getSource().getScope();
         }
-        sessionId = contextRequest.getSessionId();
-        profileId = contextRequest.getProfileId();
 
-        if (sessionId == null) {
-            sessionId = request.getParameter("sessionId");
+        if (contextRequest.getSessionId() != null) {
+            sessionId = contextRequest.getSessionId();
         }
 
+        String profileId = contextRequest.getProfileId();
         if (profileId == null) {
             // Get profile id from the cookie
             profileId = ServletCommon.getProfileIdCookieValue(request, (String) configSharingService.getProperty("profileIdCookieName"));
@@ -149,18 +141,16 @@ public class ContextJsonEndpoint {
             // Not a persona, resolve profile now
             boolean profileCreated = false;
 
-            boolean invalidateProfile = request.getParameter("invalidateProfile") != null ?
-                    new Boolean(request.getParameter("invalidateProfile")) : false;
             if (profileId == null || invalidateProfile) {
                 // no profileId cookie was found or the profile has to be invalidated, we generate a new one and create the profile in the profile service
-                profile = createNewProfile(null, response, timestamp);
+                profile = createNewProfile(null, timestamp);
                 profileCreated = true;
             } else {
                 profile = profileService.load(profileId);
                 if (profile == null) {
                     // this can happen if we have an old cookie but have reset the server,
                     // or if we merged the profiles and somehow this cookie didn't get updated.
-                    profile = createNewProfile(profileId, response, timestamp);
+                    profile = createNewProfile(profileId, timestamp);
                     profileCreated = true;
                 } else {
                     Changes changesObject = checkMergedProfile(profile, session);
@@ -170,8 +160,6 @@ public class ContextJsonEndpoint {
             }
 
             Profile sessionProfile;
-            boolean invalidateSession = request.getParameter("invalidateSession") != null ?
-                    new Boolean(request.getParameter("invalidateSession")) : false;
             if (StringUtils.isNotBlank(sessionId) && !invalidateSession) {
                 session = profileService.loadSession(sessionId, timestamp);
                 if (session != null) {
@@ -256,11 +244,9 @@ public class ContextJsonEndpoint {
             contextResponse.setSessionId(sessionId);
         }
 
-        if (contextRequest != null) {
-            Changes changesObject = handleRequest(contextRequest, session, profile, contextResponse, request, response, timestamp);
-            changes |= changesObject.getChangeType();
-            profile = changesObject.getProfile();
-        }
+        Changes changesObject = handleRequest(contextRequest, session, profile, contextResponse, request, response, timestamp);
+        changes |= changesObject.getChangeType();
+        profile = changesObject.getProfile();
 
         if ((changes & EventService.PROFILE_UPDATED) == EventService.PROFILE_UPDATED) {
             profileService.save(profile);
@@ -296,7 +282,6 @@ public class ContextJsonEndpoint {
                 }
             } else {
                 logger.warn("Couldn't find merged profile {}, falling back to profile {}", masterProfileId, currentProfile.getItemId());
-                profile = currentProfile;
                 profile.setMergedWith(null);
                 changes = EventService.PROFILE_UPDATED;
             }
@@ -379,25 +364,23 @@ public class ContextJsonEndpoint {
      * @param session
      */
     private void processOverrides(ContextRequest contextRequest, Profile profile, Session session) {
-        if (profile instanceof Persona) {
-            if (contextRequest.getProfileOverrides() != null) {
-                if (contextRequest.getProfileOverrides().getScores() != null) {
-                    profile.setScores(contextRequest.getProfileOverrides().getScores());
-                }
-                if (contextRequest.getProfileOverrides().getSegments() != null) {
-                    profile.setSegments(contextRequest.getProfileOverrides().getSegments());
-                }
-                if (contextRequest.getProfileOverrides().getProperties() != null) {
-                    profile.setProperties(contextRequest.getProfileOverrides().getProperties());
-                }
-                if (contextRequest.getSessionPropertiesOverrides() != null && session != null) {
-                    session.setProperties(contextRequest.getSessionPropertiesOverrides());
-                }
+        if (profile instanceof Persona && contextRequest.getProfileOverrides() != null) {
+            if (contextRequest.getProfileOverrides().getScores() != null) {
+                profile.setScores(contextRequest.getProfileOverrides().getScores());
+            }
+            if (contextRequest.getProfileOverrides().getSegments() != null) {
+                profile.setSegments(contextRequest.getProfileOverrides().getSegments());
+            }
+            if (contextRequest.getProfileOverrides().getProperties() != null) {
+                profile.setProperties(contextRequest.getProfileOverrides().getProperties());
+            }
+            if (contextRequest.getSessionPropertiesOverrides() != null && session != null) {
+                session.setProperties(contextRequest.getSessionPropertiesOverrides());
             }
         }
     }
 
-    private Profile createNewProfile(String existingProfileId, ServletResponse response, Date timestamp) {
+    private Profile createNewProfile(String existingProfileId, Date timestamp) {
         Profile profile;
         String profileId = existingProfileId;
         if (profileId == null) {
@@ -443,7 +426,7 @@ public class ContextJsonEndpoint {
         List<PersonalizationService.PersonalizationRequest> result = new ArrayList<>();
         for (PersonalizationService.PersonalizationRequest personalizationRequest : personalizations) {
             List<PersonalizationService.PersonalizedContent> personalizedContents = sanitizePersonalizedContentObjects(personalizationRequest.getContents());
-            if (personalizedContents != null && personalizedContents.size() > 0) {
+            if (personalizedContents != null && !personalizedContents.isEmpty()) {
                 result.add(personalizationRequest);
             }
         }
diff --git a/rest/src/main/java/org/apache/unomi/rest/EventsCollectorEndpoint.java b/rest/src/main/java/org/apache/unomi/rest/EventsCollectorEndpoint.java
index a673fd3..e0e603a 100644
--- a/rest/src/main/java/org/apache/unomi/rest/EventsCollectorEndpoint.java
+++ b/rest/src/main/java/org/apache/unomi/rest/EventsCollectorEndpoint.java
@@ -17,43 +17,33 @@
 
 package org.apache.unomi.rest;
 
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
-import org.apache.unomi.api.Event;
-import org.apache.unomi.api.EventsCollectorRequest;
-import org.apache.unomi.api.Persona;
-import org.apache.unomi.api.Profile;
-import org.apache.unomi.api.Session;
+import org.apache.unomi.api.*;
 import org.apache.unomi.api.services.ConfigSharingService;
 import org.apache.unomi.api.services.EventService;
 import org.apache.unomi.api.services.PrivacyService;
 import org.apache.unomi.api.services.ProfileService;
-import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.utils.Changes;
 import org.apache.unomi.utils.ServletCommon;
-import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.jws.WebService;
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
-import java.io.IOException;
-import java.rmi.RemoteException;
+import javax.ws.rs.core.Response;
 import java.util.Date;
 import java.util.UUID;
 
 @WebService
 @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
-@Consumes(MediaType.TEXT_PLAIN)
+@Consumes(MediaType.APPLICATION_JSON)
 @CrossOriginResourceSharing(
         allowAllOrigins = true,
         allowCredentials = true
@@ -77,36 +67,30 @@ public class EventsCollectorEndpoint {
     @Context
     HttpServletResponse response;
 
+    @OPTIONS
+    @Path("/eventcollector")
+    public Response options() {
+        return Response.status(Response.Status.NO_CONTENT).build();
+    }
+
     @GET
     @Path("/eventcollector")
-    public EventCollectorResponse get(String eventsCollectorRequestAsString, @QueryParam("timestamp") Long timestampAsString) throws IOException {
-        return doEvent(eventsCollectorRequestAsString, timestampAsString);
+    public EventCollectorResponse collectAsGet(EventsCollectorRequest eventsCollectorRequest, @QueryParam("timestamp") Long timestampAsString) {
+        return doEvent(eventsCollectorRequest, timestampAsString);
     }
 
     @POST
     @Path("/eventcollector")
-    public EventCollectorResponse post(String eventsCollectorRequestAsString, @QueryParam("timestamp") Long timestampAsLong) throws IOException {
-        return doEvent(eventsCollectorRequestAsString, timestampAsLong);
+    public EventCollectorResponse collectAsPost(EventsCollectorRequest eventsCollectorRequest, @QueryParam("timestamp") Long timestampAsLong) {
+        return doEvent(eventsCollectorRequest, timestampAsLong);
     }
 
-    private EventCollectorResponse doEvent(String eventsCollectorRequestAsString, Long timestampAsLong) throws IOException {
+    private EventCollectorResponse doEvent(EventsCollectorRequest eventsCollectorRequest, Long timestampAsLong) {
         Date timestamp = new Date();
         if (timestampAsLong != null) {
             timestamp = new Date(timestampAsLong);
         }
 
-
-        ObjectMapper mapper = CustomObjectMapper.getObjectMapper();
-        JsonFactory factory = mapper.getFactory();
-        EventsCollectorRequest eventsCollectorRequest;
-        try {
-            eventsCollectorRequest = mapper.readValue(factory.createParser(eventsCollectorRequestAsString), EventsCollectorRequest.class);
-        } catch (Exception e) {
-            if (logger.isDebugEnabled()) {
-                logger.debug("Cannot parse eventsCollectorRequest: {}", eventsCollectorRequestAsString, e);
-            }
-            throw new RemoteException("Cannot read payload. See debug level for more information");
-        }
         if (eventsCollectorRequest == null || eventsCollectorRequest.getEvents() == null) {
             throw new InternalServerErrorException("No events found");
         }
@@ -125,8 +109,8 @@ public class EventsCollectorEndpoint {
             // Get the first available scope that is not equal to systemscope to create the session otherwise systemscope will be used
             for (Event event : eventsCollectorRequest.getEvents()) {
                 if (StringUtils.isNotBlank(event.getEventType())) {
-                    if (StringUtils.isNotBlank(event.getScope()) && !event.getScope().equals("systemscope")) {
-                        scope = event.getScope();
+                    if (StringUtils.isNotBlank(event.getSourceId()) && !event.getSourceId().equals("systemscope")) {
+                        scope = event.getSourceId();
                         break;
                     } else if (event.getSource() != null && StringUtils.isNotBlank(event.getSource().getScope()) && !event.getSource().getScope().equals("systemscope")) {
                         scope = event.getSource().getScope();
@@ -134,6 +118,7 @@ public class EventsCollectorEndpoint {
                     }
                 }
             }
+            logger.debug("scope is now {}", scope);
             String cookieProfileId = ServletCommon.getProfileIdCookieValue(request, (String) configSharingService.getProperty("profileIdCookieName"));
             if (StringUtils.isNotBlank(cookieProfileId)) {
                 profile = profileService.load(cookieProfileId);
@@ -154,11 +139,13 @@ public class EventsCollectorEndpoint {
             */
         } else {
             Profile sessionProfile = session.getProfile();
+            final String errorMessage = String.format("No valid profile found or persona found for profileId=%s, aborting request !", session.getProfileId());
             if (sessionProfile.getItemId() != null) {
                 // Reload up-to-date profile
                 profile = profileService.load(sessionProfile.getItemId());
                 if (profile == null || profile instanceof Persona) {
-                    throw new InternalServerErrorException(String.format("No valid profile found or persona found for profileId=%s, aborting request !", session.getProfileId()));
+                    logger.error(errorMessage);
+                    throw new InternalServerErrorException(errorMessage);
                 }
             } else {
                 // Session uses anonymous profile, try to find profile from cookie
@@ -168,7 +155,8 @@ public class EventsCollectorEndpoint {
                 }
 
                 if (profile == null) {
-                    throw new InternalServerErrorException(String.format("No valid profile found or persona found for profileId=%s, aborting request !", session.getProfileId()));
+                    logger.error(errorMessage);
+                    throw new InternalServerErrorException(errorMessage);
                 }
             }
         }