org.openremote.foxycart.resources.FoxyCartResource.java Source code

Java tutorial

Introduction

Here is the source code for org.openremote.foxycart.resources.FoxyCartResource.java

Source

/*
 * OpenRemote, the Home of the Digital Home.
 * Copyright 2008-2016, OpenRemote Inc.
 *
 * See the contributors.txt file in the distribution for a
 * full listing of individual contributors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.openremote.foxycart.resources;

import flexjson.JSONDeserializer;
import flexjson.JSONSerializer;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.net.URLCodec;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.openremote.rest.GenericResourceResultWithErrorMessage;
import org.openremote.useraccount.domain.AccountDTO;
import org.openremote.useraccount.domain.RoleDTO;
import org.openremote.useraccount.domain.UserDTO;
import org.restlet.data.ChallengeScheme;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletConfig;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.sql.Timestamp;
import java.text.Normalizer;

@Path("/datafeed")
public class FoxyCartResource {

    public static final String INIT_PARAM_NAME_FOXYCART_KEY = "foxycart.key";
    public static final String INIT_PARAM_NAME_PASSWORD = "uas.admin.password";
    private static final String ADMIN_USER = "designer_appl";
    private static final String USER_PASSWORD = "gjhsqhghf";
    private static final int MAX_NUM_OF_UNIQUE_USER_NAMES = 50;

    protected final static Logger log = LoggerFactory.getLogger(FoxyCartResource.class);

    /*
    @GET()
    public String getFoxyCart() {
      return "Hello FoxyCart";
    }
    */

    @POST()
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.TEXT_PLAIN)
    public Response setCustomer(@FormDataParam("FoxyData") FormDataBodyPart foxyCartBody,
            @Context ServletConfig servletConfig) {
        String key = servletConfig.getInitParameter(INIT_PARAM_NAME_FOXYCART_KEY);
        String password = servletConfig.getInitParameter(INIT_PARAM_NAME_PASSWORD);

        String foxyDataString = null;
        foxyDataString = new String(decrypt(decode(foxyCartBody.getValue()), key), StandardCharsets.UTF_8);

        Document doc = parseXML(foxyDataString);

        String firstName = evaluateXPath(doc, "/foxydata/transactions/transaction/customer_first_name/text()");
        String lastName = evaluateXPath(doc, "/foxydata/transactions/transaction/customer_last_name/text()");
        String eMail = evaluateXPath(doc, "/foxydata/transactions/transaction/customer_email/text()");

        if (firstName == null) {
            String msg = "Could not find XML element 'customer_first_name'.";
            log.error(msg);
            Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("ERROR : " + msg).build();
            throw new WebApplicationException(resp);
        }

        if (lastName == null) {
            String msg = "Could not find XML element 'customer_last_name'.";
            log.error(msg);
            Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("ERROR : " + msg).build();
            throw new WebApplicationException(resp);
        }

        if (eMail == null) {
            String msg = "Could not find XML element 'customer_email'.";
            log.error(msg);
            Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
            throw new WebApplicationException(resp);
        }

        int count = 1;
        while (!createAccount(password, createUniqueUserName(firstName, lastName, count), eMail)) {
            ++count;

            if (count > MAX_NUM_OF_UNIQUE_USER_NAMES) {
                String msg = "Did not create user '" + createUniqueUserName(firstName, lastName, count)
                        + "' because reached max number ('" + MAX_NUM_OF_UNIQUE_USER_NAMES + "') of unique users.";
                log.error(msg);
                Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("ERROR : " + msg)
                        .build();
                throw new WebApplicationException(resp);
            }
        }

        return Response.status(Response.Status.OK).entity("foxy").build();
    }

    private Document parseXML(String data) {
        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();

        DocumentBuilder docBuilder = null;
        Document doc = null;
        try {
            docBuilder = docBuilderFactory.newDocumentBuilder();
            doc = docBuilder.parse(new InputSource(new StringReader(data)));
        } catch (Exception e) {
            String msg = "Failed to parse XML data.";
            log.error(msg, e);
            Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("ERROR : " + msg).build();
            throw new WebApplicationException(resp);
        }

        return doc;
    }

    private String evaluateXPath(Document doc, String xPathExpression) {
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        String text = null;

        try {
            XPathExpression expr = xpath.compile(xPathExpression);
            text = (String) expr.evaluate(doc, XPathConstants.STRING);
        } catch (XPathExpressionException e) {
        }

        return text;
    }

    private String createUserName(String firstName, String lastName) {
        firstName = removeDiacritics(firstName.toLowerCase());
        lastName = removeDiacritics(lastName.toLowerCase());

        String userName = firstName + "." + lastName;
        userName = userName.replaceAll("\\s+", ".");
        userName = userName.replaceAll("[-,_]+", ".");

        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < userName.length(); i++) {
            char c = userName.charAt(i);
            if ((c >= 'a' && c <= 'z') || c == '.') {
                builder.append(c);
            }
        }
        userName = builder.toString();

        return userName;
    }

    private String createUniqueUserName(String firstName, String lastName, int count) {
        String userName = createUserName(firstName, lastName);

        if (count == 1) {
            return userName;
        } else {
            return userName + "." + count;
        }
    }

    private byte[] decode(String data) {
        try {
            return URLCodec.decodeUrl(data.getBytes());
        } catch (DecoderException e) {
            String msg = "Invalid URL encoded data.";
            log.error(msg, e);
            Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("ERROR : " + msg).build();
            throw new WebApplicationException(resp);
        }
    }

    private byte[] decrypt(byte[] data, String key) {
        Cipher rc4 = null;
        try {
            rc4 = Cipher.getInstance("RC4");
        } catch (GeneralSecurityException e) {
            String msg = "RC4 decryption algorithm was not found.";
            log.error(msg, e);
            Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("ERROR : " + msg).build();
            throw new WebApplicationException(resp);
        }

        try {
            rc4.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(), "RC4"));
        } catch (InvalidKeyException e) {
            String msg = "Invalid key. Key has to be configured in web.xml. In addition make sure "
                    + "Java Cryptography Extension (JCE) unlimited strength jurisdiction policy files have been installed.";
            log.error(msg, e);
            Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("ERROR : " + msg).build();
            throw new WebApplicationException(resp);
        }

        try {
            return rc4.doFinal(data);
        } catch (GeneralSecurityException e) {
            String msg = "Failed to decrypt data with RC4 algorithm because of invalid data. In additon make sure "
                    + "Java Cryptography Extension (JCE) unlimited strength jurisdiction policy files have been installed.";
            log.error(msg, e);
            Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("ERROR : " + msg).build();
            throw new WebApplicationException(resp);
        }
    }

    private boolean createAccount(String password, String userName, String userEmail) {
        UserDTO user = new UserDTO();
        user.setUsername(userName);
        user.setPassword(new Md5PasswordEncoder().encodePassword(USER_PASSWORD, userName));
        user.setEmail(userEmail);
        user.setRegisterTime(new Timestamp(System.currentTimeMillis()));
        user.addRole(new RoleDTO("ROLE_ADMIN", Long.valueOf(3)));
        user.setAccount(new AccountDTO());

        ClientResource cr = new ClientResource("http://designer.openremote.com/uas/rest/user");
        cr.setChallengeResponse(ChallengeScheme.HTTP_BASIC, ADMIN_USER, password);
        Representation rep = new JsonRepresentation(new JSONSerializer().exclude("*.class").deepSerialize(user));
        Representation r = null;
        try {
            r = cr.post(rep);
        } catch (ResourceException e) {
            String msg = "Rest call (POST) 'http://designer.openremote.com/uas/rest/user' failed.";
            log.error(msg, e);
            Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("ERROR : " + msg).build();
            throw new WebApplicationException(resp);
        }
        String str = null;
        try {
            str = r.getText();
        } catch (IOException e) {
            String msg = "Failed to deserialize response from rest call (POST) 'http://designer.openremote.com/uas/rest/user'.";
            log.error(msg, e);
            Response resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("ERROR" + msg).build();
            throw new WebApplicationException(resp);
        }
        GenericResourceResultWithErrorMessage res = new JSONDeserializer<GenericResourceResultWithErrorMessage>()
                .use(null, GenericResourceResultWithErrorMessage.class).use("result", Long.class).deserialize(str);
        if (res.getErrorMessage() != null) {

            String msg = "Account creation failed (username='" + userName + "', E-Mail='" + userEmail + "') : "
                    + res.getErrorMessage();
            System.out.println(msg);
            log.warn(msg);

            return false;
        } else {
            String msg = "Created user account (username='" + userName + "', E-Mail='" + userEmail + "') oid : "
                    + res.getResult();
            System.out.println(msg);
            log.info(msg);

            return true;
        }
    }

    private String removeDiacritics(String text) {
        // characters     

        text = text.replace("\u00E4", "ae");
        text = text.replace("\u00F1", "ny");
        text = text.replace("\u00F6", "oe");
        text = text.replace("\u00FC", "ue");
        text = text.replace("\u00FF", "yu");

        text = Normalizer.normalize(text, Normalizer.Form.NFD);
        text = text.replaceAll("\\p{M}", "");

        text = text.replace("\u00DF", "ss");
        text = text.replace("\u00C6", "AE");
        text = text.replace("\u00E6", "ae");
        text = text.replace("\u0132", "IJ");
        text = text.replace("\u0133", "ij");
        text = text.replace("\u0152", "Oe");
        text = text.replace("\u0153", "oe");

        // ??

        text = text.replace("\u00D0", "D");
        text = text.replace("\u0110", "D");
        text = text.replace("\u00F0", "d");
        text = text.replace("\u0111", "d");
        text = text.replace("\u0126", "H");
        text = text.replace("\u0127", "h");

        //  ?

        text = text.replace("\u0131", "i");
        text = text.replace("\u0138", "k");
        text = text.replace("\u013F", "L");
        text = text.replace("\u0141", "L");
        text = text.replace("\u0140", "l");
        text = text.replace("\u0142", "l");

        // 

        text = text.replace("\u014A", "N");
        text = text.replace("\u0149", "n");
        text = text.replace("\u014B", "n");
        text = text.replace("\u00D8", "O");
        text = text.replace("\u00F8", "o");
        text = text.replace("\u017F", "s");

        // 

        text = text.replace("\u00DE", "T");
        text = text.replace("\u0166", "T");
        text = text.replace("\u00FE", "t");
        text = text.replace("\u0167", "t");

        return text;
    }
}