com.adobe.communities.ugc.migration.importer.ScoresImportServlet.java Source code

Java tutorial

Introduction

Here is the source code for com.adobe.communities.ugc.migration.importer.ScoresImportServlet.java

Source

/*************************************************************************
 *
 * ADOBE SYSTEMS INCORPORATED
 * Copyright 2015 Adobe Systems Incorporated
 * All Rights Reserved.
 *
 * NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the
 * terms of the Adobe license agreement accompanying it.  If you have received this file from a
 * source other than Adobe, then your use, modification, or distribution of it requires the prior
 * written permission of Adobe.
 **************************************************************************/
package com.adobe.communities.ugc.migration.importer;

import com.adobe.cq.social.scoring.api.ScoreOperation;
import com.adobe.cq.social.srp.SocialResourceProvider;
import com.adobe.cq.social.ugcbase.SocialUtils;
import com.adobe.granite.security.user.UserProperties;
import com.adobe.granite.security.user.UserPropertiesManager;
import com.adobe.granite.security.user.UserPropertiesService;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestParameter;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.RepositoryException;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component(label = "UGC Migration Profile Scores Importer", description = "Accepts a json file containing profile scores and applies them to stored profiles", specVersion = "1.1")
@Service
@Properties({ @Property(name = "sling.servlet.paths", value = "/services/social/scores/import") })
public class ScoresImportServlet extends SlingAllMethodsServlet {

    private static final Logger LOG = LoggerFactory.getLogger(ScoresImportServlet.class);

    @Reference
    private ResourceResolverFactory rrf;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY, policy = ReferencePolicy.STATIC)
    private UserPropertiesService userPropertiesService;

    /**
     * The post operation accepts a json file, parses it and applies the profile scores to local profiles
     * @param request - the request
     * @param response - the response
     * @throws javax.servlet.ServletException
     * @throws java.io.IOException
     */
    protected void doPost(final SlingHttpServletRequest request, final SlingHttpServletResponse response)
            throws ServletException, IOException {

        final ResourceResolver resolver = request.getResourceResolver();

        UGCImportHelper.checkUserPrivileges(resolver, rrf);

        final RequestParameter[] fileRequestParameters = request.getRequestParameters("file");
        if (fileRequestParameters != null && fileRequestParameters.length > 0
                && !fileRequestParameters[0].isFormField()
                && fileRequestParameters[0].getFileName().endsWith(".json")) {
            final InputStream inputStream = fileRequestParameters[0].getInputStream();
            final JsonParser jsonParser = new JsonFactory().createParser(inputStream);
            JsonToken token = jsonParser.nextToken(); // get the first token
            if (token.equals(JsonToken.START_OBJECT)) {
                try {
                    final UserPropertiesManager userManager = userPropertiesService
                            .createUserPropertiesManager(resolver);
                    importFile(jsonParser, userManager, resolver);
                } catch (RepositoryException e) {
                    throw new ServletException("Unable to communicate with Jcr repository", e);
                } catch (final Exception e) {
                    throw new ServletException("Problem!", e);
                }
            } else {
                throw new ServletException("Expected a start object token, got " + token);
            }
        } else {
            throw new ServletException("Expected to get a json file in post request");
        }
    }

    private Map<String, Boolean> getScoreTypes(final ResourceResolver resolver) {
        Map<String, Boolean> scoreTypes = new HashMap<String, Boolean>();
        final Resource rootNode = resolver.getResource("/etc/segmentation/score");
        if (null == rootNode) {
            return null;
        }
        final Iterable<Resource> scoreNodes = rootNode.getChildren();
        for (final Resource scoreNode : scoreNodes) {
            ValueMap vm = scoreNode.adaptTo(ValueMap.class);
            final Resource content = scoreNode.getChild("jcr:content");
            if (null == content) {
                continue;
            }
            if (content.isResourceType("social/scoring/components/scoringpage")) {
                final ValueMap valueMap = content.adaptTo(ValueMap.class);
                if (valueMap.containsKey("sname")) {
                    final String[] scoreNames = (String[]) valueMap.get("sname");
                    scoreTypes.put(scoreNames[0], true);
                }
            }
        }
        return scoreTypes;
    }

    private void importFile(final JsonParser jsonParser, final UserPropertiesManager userManager,
            final ResourceResolver resolver) throws ServletException, IOException, RepositoryException {
        Map<String, Boolean> scoreTypes = getScoreTypes(resolver);
        JsonToken token = jsonParser.nextToken();

        while (!token.equals(JsonToken.END_OBJECT)) {
            final String authId = jsonParser.getCurrentName();
            token = jsonParser.nextToken();
            if (!token.equals(JsonToken.START_OBJECT)) {
                throw new ServletException("Expected to see start object, got " + token);
            }
            final Map<String, Long> scores = new HashMap<String, Long>();
            token = jsonParser.nextToken();
            while (!token.equals(JsonToken.END_OBJECT)) {
                final String scoreName = jsonParser.getCurrentName();
                jsonParser.nextToken();
                final Long scoreValue = jsonParser.getLongValue();
                scores.put(scoreName, scoreValue);
                if (!scoreTypes.containsKey(scoreName)) {
                    LOG.warn(
                            "A score of type [{}] was imported for [{}], but that score type hasn't been configured "
                                    + "on this server",
                            scoreName, authId);
                }
                token = jsonParser.nextToken();
            }
            updateProfileScore(authId, scores, userManager, resolver);
            token = jsonParser.nextToken();
        }
    }

    private void updateProfileScore(final String authId, final Map<String, Long> scores,
            final UserPropertiesManager userManager, final ResourceResolver resolver) throws RepositoryException {
        List<ScoreOperation> scoreOperations = new ArrayList<ScoreOperation>();
        for (final Map.Entry<String, Long> entry : scores.entrySet()) {
            ScoreOperation scoreOperation = new ScoreOperation();
            scoreOperation.setScoreName(entry.getKey());
            scoreOperation.setAbsolute(true);
            scoreOperation.setScoreValue(entry.getValue());
            scoreOperations.add(scoreOperation);
        }
        setPoints(authId, scoreOperations, resolver, userManager);
    }

    public void setPoints(final String userId, final List<ScoreOperation> scoreOperations,
            final ResourceResolver resourceResolver, final UserPropertiesManager userManager)
            throws RepositoryException {
        UserProperties userProps = userManager.getUserProperties(userId, "profile");

        final Resource scoreResource = getScoreResource(resourceResolver, userProps);
        if (null != scoreResource) {
            final SocialResourceProvider socialResourceProvider = getSocialResourceProvider(scoreResource);

            for (final ScoreOperation operation : scoreOperations) {
                try {
                    ModifiableValueMap modifiableValueMap = scoreResource.adaptTo(ModifiableValueMap.class);
                    modifiableValueMap.put(operation.getScoreName(), operation.getScoreValue());
                    socialResourceProvider.commit(resourceResolver);
                } catch (final PersistenceException e) {
                    LOG.error("Failed to execute scoring operation {} on {}",
                            new Object[] { operation.getScoreName(), scoreResource.getPath() }, e);
                }

            }
            try {
                socialResourceProvider.commit(resourceResolver);
            } catch (final PersistenceException e) {
                LOG.error("Failed to commit score operations", e);
            }
        } else {
            LOG.debug("could not update score, profile/score unavailable.");
        }

    }

    private SocialResourceProvider getSocialResourceProvider(final Resource resource) {
        SocialResourceProvider socialResourceProvider = null;
        final SocialUtils socialUtils = resource.getResourceResolver().adaptTo(SocialUtils.class);
        if (socialUtils != null) {
            socialResourceProvider = socialUtils.getConfiguredProvider(resource);
        }
        return socialResourceProvider;
    }

    private Resource getScoreResource(final ResourceResolver resolver, UserProperties user)
            throws RepositoryException {

        Resource resource = null;
        if (null != user) {
            final SocialUtils socialUtils = resolver.adaptTo(SocialUtils.class);
            final Resource userResource = user.getResource("");
            if (userResource != null) {
                final SocialResourceProvider socialResourceProvider = getSocialResourceProvider(userResource);
                if (socialUtils != null) {
                    final String path = socialUtils.resourceToUGCStoragePath(userResource) + "/scoring";
                    resource = resolver.getResource(path);
                    LOG.trace("Getting scoring resource: {}", path);

                    if (resource == null) {
                        resource = createScoringResource(resolver, socialResourceProvider, path, "socialHolder");
                    }
                }
            }
        }

        return resource;
    }

    private static Resource createScoringResource(final ResourceResolver resolver, final SocialResourceProvider srp,
            final String path, final String type) {
        Resource resource = null;
        try {
            LOG.trace("Creating scoring resource: {}", path);
            Map<String, Object> props = new HashMap<String, Object>();
            props.put(SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE, type);
            srp.create(resolver, path, props);
            srp.commit(resolver);
            resource = resolver.getResource(path);
        } catch (final PersistenceException e) {
            LOG.error("Failed to create scoring nodes for {}", new Object[] { path }, e);
        }
        return resource;
    }

}