org.occiware.clouddesigner.occi.linkeddata.connector.LdprojectConnector.java Source code

Java tutorial

Introduction

Here is the source code for org.occiware.clouddesigner.occi.linkeddata.connector.LdprojectConnector.java

Source

/**
 * Copyright (c) 2016 Inria
 *  
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 * - Philippe Merle <philippe.merle@inria.fr>
 *
 * Generated at Fri Jun 03 17:38:12 CEST 2016 from platform:/resource/org.occiware.clouddesigner.occi.linkeddata/model/linkeddata.occie by org.occiware.clouddesigner.occi.gen.connector
 */
package org.occiware.clouddesigner.occi.linkeddata.connector;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.ws.rs.NotFoundException;
import javax.ws.rs.WebApplicationException;

import org.apache.commons.io.IOUtils;
import org.oasis.datacore.common.context.SimpleRequestContextProvider;
import org.oasis.datacore.rest.api.DCResource;
import org.oasis.datacore.rest.api.DatacoreApi;
import org.oasis.datacore.rest.api.util.UriHelper;
import org.oasis.datacore.rest.client.DatacoreCachedClient;
import org.oasis.datacore.rest.client.cxf.mock.AuthenticationHelper;
import org.occiware.clouddesigner.occi.Link;
import org.occiware.clouddesigner.occi.infrastructure.Compute;
import org.occiware.clouddesigner.occi.linkeddata.Lddatabaselink;
import org.occiware.clouddesigner.occi.linkeddata.Ldproject;
import org.occiware.clouddesigner.occi.linkeddata.Ldprojectlink;
import org.occiware.clouddesigner.occi.linkeddata.Lifecycle;
import org.occiware.clouddesigner.occi.linkeddata.Robustness;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.google.common.collect.ImmutableMap;

/**
 * Connector implementation for the OCCI kind:
 * - scheme: http://occiware.org/linkeddata#
 * - term: LDProject
 * - title: 
 */
public class LdprojectConnector extends org.occiware.clouddesigner.occi.linkeddata.impl.LdprojectImpl {
    /**
     * Initialize the logger.
     */
    private static Logger LOGGER = LoggerFactory.getLogger(LdprojectConnector.class);

    private static ClassPathXmlApplicationContext ctx = null;
    private DatacoreCachedClient ldc = null;
    private URI ldContainerUrl = null;
    private String ldContainerUrlString;

    /**
     * Constructs a LDProject connector.
     */
    LdprojectConnector() {
        // getOrBuildDatacoreClient() { if ctx == null or ldContainerUrlString != LDNode.url...
        LOGGER.debug("Constructor called on " + this);
        //System.setProperty("datacoreApiClient.containerUrl", "blabla"); // then LDNode.url

        synchronized (LdprojectConnector.class) {
            if (ctx == null) {
                ctx = new ClassPathXmlApplicationContext("oasis-datacore-rest-client-custom-context.xml");
            }
        }
        ldc = (DatacoreCachedClient) ctx.getBean("datacoreApiCachedJsonClient");
        ldContainerUrlString = ctx.getBeanFactory().resolveEmbeddedValue("${datacoreApiClient.containerUrl}");
        String ldBaseUrlString = ctx.getBeanFactory().resolveEmbeddedValue("${datacoreApiClient.baseUrl}");
        try {
            ldContainerUrl = new URI(ldContainerUrlString);
            LOGGER.warn("Starting connector, using Linked Data Core at " + ldBaseUrlString + " with containerUrl "
                    + ldContainerUrlString);
        } catch (URISyntaxException e) {
            LOGGER.error("bad conf " + ldContainerUrlString, e);
            e.printStackTrace();
        }
    }

    //
    // OCCI CRUD callback operations.
    //

    /**
     * Called when this LDProject instance is completely created.
     */
    @Override
    public void occiCreate() {
        LOGGER.debug("occiCreate() called on " + this);

        this.update(); // creates or updates
    }

    /**
     * Called when this LDProject instance must be retrieved.
     */
    @Override
    public void occiRetrieve() {
        LOGGER.debug("occiRetrieve() called on " + this);

        try {
            authenticate();

            DCResource ldResource = getExistingOrNew("dcmp:Project_0", this.name);
            if (ldResource.getVersion() == null || ldResource.getVersion() < 0) {
                return; // does not yet exist, nothing to update
            }

            retrieveAttributes(ldResource);

        } catch (IllegalArgumentException e) {
            LOGGER.error("IllegalArgumentException", e);
            e.printStackTrace();
        } catch (WebApplicationException e) {
            System.out.println(readBodyAsString(e));
            LOGGER.error("WebApplicationException", e);
            e.printStackTrace();
        }
    }

    /**
     * Called when this LDProject instance is completely updated.
     */
    @Override
    public void occiUpdate() {
        LOGGER.debug("occiUpdate() called on " + this);

        this.update(); // creates or updates
    }

    /**
     * Called when this LDProject instance will be deleted.
     */
    @Override
    public void occiDelete() {
        LOGGER.debug("occiDelete() called on " + this);

        try {

            authenticate();

            // getting DCResource (especially version) :
            DCResource ldResource = ldc.getData("dcmp:Project_0", this.name);

            // deleting it :
            ldc.deleteData(ldResource);

        } catch (NotFoundException e) {
            LOGGER.error("NotFoundException", e);
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            LOGGER.error("IllegalArgumentException", e);
            e.printStackTrace();
        } catch (WebApplicationException e) {
            System.out.println(readBodyAsString(e));
            LOGGER.error("WebApplicationException", e);
            e.printStackTrace();
        }
    }

    //
    // LDProject actions.
    //

    /**
     * Implement OCCI action:
      * - scheme: http://occiware.org/linkeddata/LDProject/action#
      * - term: publish
      * - title: 
     */
    @Override
    public void publish() {
        LOGGER.debug("Action publish() called on " + this);

        if (this.getLifecycle() == Lifecycle.PUBLISHED) {
            return; // TODO explode ?
        }

        try {

            authenticate();

            // getting DCResource (especially version) :
            DCResource ldResource = ldc.getData("dcmp:Project_0", this.name);

            // updating attributes :
            ArrayList<String> frozenModelNames = new ArrayList<String>(2);
            frozenModelNames.add("*");
            ldResource.set("dcmp:frozenModelNames", frozenModelNames);

            // saving OCCI resource as DCResource :
            ldResource = ldc.putDataInType(ldResource); // NOT POST else list values are merged, rather replace

            this.setLifecycle(Lifecycle.PUBLISHED);

        } catch (NotFoundException e) {
            LOGGER.error("NotFoundException", e);
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            LOGGER.error("IllegalArgumentException", e);
            e.printStackTrace();
        } catch (WebApplicationException e) {
            System.out.println(readBodyAsString(e));
            LOGGER.error("WebApplicationException", e);
            e.printStackTrace();
        }
    }

    /**
     * Implement OCCI action:
      * - scheme: http://occiware.org/linkeddata/LDProject/action#
      * - term: unpublish
      * - title: 
     */
    @Override
    public void unpublish() {
        LOGGER.debug("Action unpublish() called on " + this);

        if (this.getLifecycle() == Lifecycle.DRAFT) {
            return; // TODO explode ?
        }

        try {

            authenticate();

            // getting DCResource (especially version) :
            DCResource ldResource = ldc.getData("dcmp:Project_0", this.name);

            // updating attributes :
            ldResource.set("dcmp:frozenModelNames", new ArrayList<String>(2));

            // saving OCCI resource as DCResource :
            ldResource = ldc.putDataInType(ldResource); // NOT POST else list values are merged, rather replace

            this.setLifecycle(Lifecycle.DRAFT);

        } catch (NotFoundException e) {
            LOGGER.error("NotFoundException", e);
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            LOGGER.error("IllegalArgumentException", e);
            e.printStackTrace();
        } catch (WebApplicationException e) {
            System.out.println(readBodyAsString(e));
            LOGGER.error("WebApplicationException", e);
            e.printStackTrace();
        }
    }

    /**
     * Implement OCCI action:
      * - scheme: http://occiware.org/linkeddata/LDProject/action#
      * - term: update
      * - title: 
     */
    @Override
    public void update() {
        LOGGER.debug("Action update() called on " + this);

        try {
            authenticate();

            DCResource ldResource = getExistingOrNew("dcmp:Project_0", this.name);

            updateAttributes(ldResource);

            createOrUpdate(ldResource); // saving OCCI resource as DCResource

        } catch (IllegalArgumentException e) {
            LOGGER.error("IllegalArgumentException", e);
            e.printStackTrace();
        } catch (WebApplicationException e) {
            System.out.println(readBodyAsString(e));
            LOGGER.error("WebApplicationException", e);
            e.printStackTrace();
        }
    }

    private DCResource getExistingOrNew(String modelType, String name) throws WebApplicationException {
        if (this.name == null || this.name.trim().equals("")) {
            throw new IllegalArgumentException("LDProject name must not be empty");
        }

        DCResource resource;
        try {
            resource = ldc.getData(modelType, this.name); // getting DCResource (especially version)
        } catch (NotFoundException e) {
            // preparing new :
            resource = DCResource.create(ldContainerUrl, "dcmp:Project_0", this.name);
        }
        return resource;
    }

    /**
     * 
     * @param resource must come from getExistingOrNew()
     * @throws WebApplicationException
     */
    private void createOrUpdate(DCResource resource) throws WebApplicationException {
        if (resource.getVersion() == null || resource.getVersion() < 0) {
            resource = ldc.postDataInType(resource); // create
        } else {
            resource = ldc.putDataInType(resource); // NOT POST else list values are merged, rather replace
        }
    }

    /**
     * 
     * @param resource must come from getExistingOrNew()
     */
    private void updateAttributes(DCResource resource) {
        resource.set("dcmpv:name", this.getName()); // (actually only if creation)         
        ///resource.set("dcmp:frozenModelNames", ); // NO ONLY ACTIONS ELSE VOIDS VALUE
        resource.set("dcmpvdb:robust", this.getRobustness() == Robustness.CLUSTER);

        ///resource.set("dcmpvdb:uri", this.dburi); // rather using links :
        String ldDbUri = null;
        if (this.links != null) { // ex. in Mart
            List<Link> lddLinks = this.links.stream()
                    .filter(l -> l instanceof Lddatabaselink && l.getTarget() instanceof Compute)
                    .collect(Collectors.toList());
            if (!lddLinks.isEmpty()) {
                Lddatabaselink lddLink = (Lddatabaselink) lddLinks.iterator().next(); // first one matters only
                Compute customSecondaryCompute = (Compute) lddLink.getTarget();
                if (customSecondaryCompute.getHostname() == null
                        || customSecondaryCompute.getHostname().trim().length() == 0) {
                    throw new RuntimeException("Lddatabaselink's target Compute has no hostname");
                }
                ldDbUri = "mongodb://" + customSecondaryCompute.getHostname() + ":" + lddLink.getPort() + "/"
                        + lddLink.getDatabase();
            }
        }
        resource.set("dcmpvdb:uri", ldDbUri);

        LinkedHashSet<String> lvp = new LinkedHashSet<String>();
        @SuppressWarnings("unchecked")
        Collection<String> lvpFound = (Collection<String>) resource.get("dcmp:localVisibleProjects"); // else java.lang.ClassCastException: java.util.LinkedHashSet cannot be cast to java.util.List !
        if (lvpFound == null) {
            lvp = new LinkedHashSet<String>();
            lvp.add(UriHelper.buildUri(ldContainerUrl, "dcmp:Project_0", "oasis.meta")); // all projects must see metamodel
        } else {
            lvp = new LinkedHashSet<String>(lvpFound);
        }
        if (this.links != null) { // ex. in Mart
            List<String> ldpLinkTargetProjectUris = this.links.stream()
                    .filter(l -> l instanceof Ldprojectlink && l.getTarget() instanceof Ldproject)
                    .map(ldpl -> UriHelper.buildUri(ldContainerUrl, "dcmp:Project_0",
                            ((Ldproject) ldpl.getTarget()).getName()))
                    .collect(Collectors.toList());
            lvp.addAll(ldpLinkTargetProjectUris);
        }
        resource.set("dcmp:localVisibleProjects", lvp);
    }

    /**
     * 
     * @param resource must come from getExistingOrNew()
     */
    private void retrieveAttributes(DCResource resource) {
        this.setName((String) resource.get("dcmpv:name"));
        @SuppressWarnings("unchecked")
        List<String> frozenModelNames = (List<String>) resource.get("dcmp:frozenModelNames");
        this.setLifecycle(
                frozenModelNames != null && frozenModelNames.contains("*") ? Lifecycle.PUBLISHED : Lifecycle.DRAFT);
        Boolean isRobust = (Boolean) resource.get("dcmpvdb:robust");
        this.setRobustness(isRobust != null && isRobust ? Robustness.CLUSTER : Robustness.NONE); // TODO Robustness.NODE vs high write ?

        ///resource.set("dcmpvdb:uri", this.dburi); // rather using links :
        String ldDbUri = (String) resource.get("dcmpvdb:uri");
        if (ldDbUri != null) {
            Pattern p = Pattern.compile("mongodb://(.+):(.+)/(.+)");
            Matcher m = p.matcher(ldDbUri);
            if (m.find()) {
                String hostname = m.group(1);
                String portString = m.group(2);
                String database = m.group(3);
                int port;
                try {
                    port = Integer.parseInt(portString);
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                    port = 27017; // mongo default
                }
                List<Link> lddLinks = this.links.stream().filter(l -> l instanceof Lddatabaselink)
                        .collect(Collectors.toList());
                Lddatabaselink sameLddLinkFound = null;
                List<Lddatabaselink> wrongLddLinks = new ArrayList<Lddatabaselink>(3);
                for (Link link : lddLinks) {
                    Lddatabaselink lddLink = (Lddatabaselink) link;
                    Compute customSecondaryCompute = (Compute) link.getTarget(); // should be a Compute
                    if (customSecondaryCompute != null && hostname.equals(customSecondaryCompute.getHostname())) {
                        if (port == lddLink.getPort() && database.equals(lddLink.getDatabase())) {
                            sameLddLinkFound = lddLink;
                            continue;
                        }
                    }
                    wrongLddLinks.add(lddLink);
                }
                // TODO delete wrongLddLinks (but not their Computes)
                if (sameLddLinkFound == null) {
                    // TODO find compute in conf (or ask provisioning server ???) or create it
                    // and create link
                } // else nothing to do
            }
        }

        // TODO discovery of all projects ?!?
        /*LinkedHashSet<String> lvp = new LinkedHashSet<String>();
        @SuppressWarnings("unchecked")
        List<String> lvpFound = (List<String>) resource.get("dcmp:localVisibleProjects");
        if (lvpFound == null) {
           lvp = new LinkedHashSet<String>();
           lvp.add(UriHelper.buildUri(ldContainerUrl, "dcmp:Project_0", "oasis.meta")); // all projects must see metamodel
        } else {
           lvp = new LinkedHashSet<String>(lvpFound);
        }
        List<String> ldpLinkTargetProjectUris = this.links.stream()
        .filter(l -> l instanceof Ldprojectlink && l.getTarget() instanceof Ldproject)
        .map(ldpl -> UriHelper.buildUri(ldContainerUrl, "dcmp:Project_0", ((Ldproject) ldpl.getTarget()).getName()))
        .collect(Collectors.toList());
        lvp.addAll(ldpLinkTargetProjectUris);
        resource.set("dcmp:localVisibleProjects", lvp);*/
    }

    private void authenticate() {
        SimpleRequestContextProvider.setSimpleRequestContext(
                new ImmutableMap.Builder<String, Object>().put(DatacoreApi.PROJECT_HEADER, "oasis.meta") // else no write
                        // NB. auth doesn't work like that
                        .build()); // else "There is no context" in CxfRequestContextProvider l63, TODO simpler ex. in client

        AuthenticationHelper.loginBasic("admin", "admin");
        //AuthenticationHelper.login("Bearer <token>");
    }

    public static String readBodyAsString(WebApplicationException waex) {
        Object entity = waex.getResponse().getEntity();
        if (entity instanceof String) {
            return (String) entity;
        }
        if (entity instanceof InputStream) {
            try {
                return IOUtils.toString((InputStream) entity);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        throw new IllegalArgumentException(); // when ??
    }

}