org.eclipse.winery.repository.resources.artifacts.GenericArtifactsResource.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.winery.repository.resources.artifacts.GenericArtifactsResource.java

Source

/*******************************************************************************
 * Copyright (c) 2012-2013 University of Stuttgart.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and the Apache License 2.0 which both accompany this distribution,
 * and are available at http://www.eclipse.org/legal/epl-v10.html
 * and http://www.apache.org/licenses/LICENSE-2.0
 *
 * Contributors:
 *     Oliver Kopp - initial API and implementation
 *******************************************************************************/
package org.eclipse.winery.repository.resources.artifacts;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.winery.common.RepositoryFileReference;
import org.eclipse.winery.common.Util;
import org.eclipse.winery.common.ids.Namespace;
import org.eclipse.winery.common.ids.XMLId;
import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
import org.eclipse.winery.common.ids.definitions.NodeTypeId;
import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
import org.eclipse.winery.generators.ia.Generator;
import org.eclipse.winery.model.tosca.TDeploymentArtifact;
import org.eclipse.winery.model.tosca.TEntityTemplate.Properties;
import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact;
import org.eclipse.winery.model.tosca.TInterface;
import org.eclipse.winery.model.tosca.TNodeType;
import org.eclipse.winery.repository.Utils;
import org.eclipse.winery.repository.backend.BackendUtils;
import org.eclipse.winery.repository.backend.Repository;
import org.eclipse.winery.repository.backend.ResourceCreationResult;
import org.eclipse.winery.repository.backend.filebased.FileUtils;
import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId;
import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
import org.eclipse.winery.repository.resources.AbstractComponentsResource;
import org.eclipse.winery.repository.resources.IHasTypeReference;
import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource;
import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource;
import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplateResource;
import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource;
import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource;
import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource;
import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
import org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.NodeTemplateResource;
import org.restdoc.annotations.RestDoc;
import org.restdoc.annotations.RestDocParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;

import com.sun.jersey.api.view.Viewable;

/**
 * Resource handling both deployment and implementation artifacts
 * 
 */
public abstract class GenericArtifactsResource<ArtifactResource extends GenericArtifactResource<ArtifactT>, ArtifactT>
        extends EntityWithIdCollectionResource<ArtifactResource, ArtifactT> {

    private static final Logger logger = LoggerFactory.getLogger(GenericArtifactsResource.class);

    protected final INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource resWithNamespace;

    public GenericArtifactsResource(Class<ArtifactResource> entityResourceTClazz, Class<ArtifactT> entityTClazz,
            List<ArtifactT> list,
            INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) {
        super(entityResourceTClazz, entityTClazz, list,
                GenericArtifactsResource.getAbstractComponentInstanceResource(res));
        this.resWithNamespace = res;
    }

    // @formatter:off

    /**
     * @return TImplementationArtifact | TDeploymentArtifact (XML) | URL of generated IA zip (in case of autoGenerateIA)
     */
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.TEXT_XML)
    @RestDoc(methodDescription = "Creates a new implementation/deployment artifact. "
            + "If an implementation artifact with the same name already exists, it is <em>overridden</em>.")
    @SuppressWarnings("unchecked")
    public Response onPost(
            @FormParam("artifactName") @RestDocParam(description = "This is the name of the implementation/deployment artifact. "
                    + "Is <em>also</em>used as prefix of the name of the corresponding artifact template if no specific template is provided. "
                    + "In contrast to CS01, we require a artifactName also for the implementationArtifact to be able to properly referencing it.") String artifactNameStr,

            @FormParam("artifactTemplate") @RestDocParam(description = "QName of the artifact Template - used by Winery Backend instead of artifactTemplateName + artifactTemplateNS") String artifactTemplate,

            @FormParam("artifactTemplateName") @RestDocParam(description = "if provided and autoCreateArtifactTemplate, a template of this id localname and artifactTemplateNS generated. "
                    + "Winery always sends this string if auto creation is desired.") String artifactTemplateName,

            @FormParam("artifactTemplateNS") String artifactTemplateNS,

            @FormParam("autoCreateArtifactTemplate") @RestDocParam(description = "if empty, no, or false, no artifact template is created. "
                    + "An artifact type has to be given in that case. "
                    + "Furthermore, an artifact template name + artifact template namespace has to be provided. "
                    + "Otherwise, the artifactNameStr is used as name for the artifact and a <em>new</em> artifact template is created having {@code <artifactNameString>Template} as name") String autoCreateArtifactTemplate,

            @FormParam("artifactType") @RestDocParam(description = "QName of the type, format: {namespace}localname. "
                    + "Optional if artifactTemplateName + artifactTempalteNS is provided") String artifactTypeStr,

            @FormParam("artifactSpecificContent") @RestDocParam(description = "<em>XML</em> snippet that should be put inside the artifact XML in the TOSCA serialization. "
                    + "This feature will be removed soon. "
                    + "TODO: This only works if there is a single child element expected and not several elements. "
                    + "Future versions of the Winery will support arbitrary content there.") String artifactSpecificContent,

            @FormParam("interfaceName") String interfaceNameStr,

            @FormParam("operationName") String operationNameStr,

            @FormParam("autoGenerateIA") @RestDocParam(description = "If not empty, the IA generator will be called") String autoGenerateIA,

            @FormParam("javapackage") @RestDocParam(description = "The Java package to use for IA generation") String javapackage,

            @Context UriInfo uriInfo) {
        // we assume that the parent ComponentInstance container exists

        // @formatter:on

        if (StringUtils.isEmpty(artifactNameStr)) {
            return Response.status(Status.BAD_REQUEST).entity("Empty artifactName").build();
        }
        if (StringUtils.isEmpty(artifactTypeStr)) {
            if (StringUtils.isEmpty(artifactTemplateName) || StringUtils.isEmpty(artifactTemplateNS)) {
                if (StringUtils.isEmpty(artifactTemplate)) {
                    return Response.status(Status.BAD_REQUEST)
                            .entity("No artifact type given and no template given. Cannot guess artifact type")
                            .build();
                }
            }
        }

        if (!StringUtils.isEmpty(autoGenerateIA)) {
            if (StringUtils.isEmpty(javapackage)) {
                return Response.status(Status.BAD_REQUEST)
                        .entity("no java package name supplied for IA auto generation.").build();
            }
            if (StringUtils.isEmpty(interfaceNameStr)) {
                return Response.status(Status.BAD_REQUEST)
                        .entity("no interface name supplied for IA auto generation.").build();
            }
        }

        // convert second calling form to first calling form
        if (!StringUtils.isEmpty(artifactTemplate)) {
            QName qname = QName.valueOf(artifactTemplate);
            artifactTemplateName = qname.getLocalPart();
            artifactTemplateNS = qname.getNamespaceURI();
        }

        Document doc = null;

        // check artifact specific content for validity
        // if invalid, abort and do not create anything
        if (!StringUtils.isEmpty(artifactSpecificContent)) {
            try {
                DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
                InputSource is = new InputSource();
                StringReader sr = new StringReader(artifactSpecificContent);
                is.setCharacterStream(sr);
                doc = db.parse(is);
            } catch (Exception e) {
                // FIXME: currently we allow a single element only. However, the content should be internally wrapped by an (arbitrary) XML element as the content will be nested in the artifact element, too
                GenericArtifactsResource.logger.debug("Invalid content", e);
                return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
            }
        }

        // determine artifactTemplate and artifactType

        ArtifactTypeId artifactTypeId;
        ArtifactTemplateId artifactTemplateId = null;
        ArtifactTemplateResource artifactTemplateResource = null;

        boolean doAutoCreateArtifactTemplate = !(StringUtils.isEmpty(autoCreateArtifactTemplate)
                || autoCreateArtifactTemplate.equalsIgnoreCase("no")
                || autoCreateArtifactTemplate.equalsIgnoreCase("false"));
        if (!doAutoCreateArtifactTemplate) {
            // no auto creation
            if (!StringUtils.isEmpty(artifactTemplateName) && !StringUtils.isEmpty(artifactTemplateNS)) {
                QName artifactTemplateQName = new QName(artifactTemplateNS, artifactTemplateName);
                artifactTemplateId = BackendUtils.getTOSCAcomponentId(ArtifactTemplateId.class,
                        artifactTemplateQName);
            }
            if (StringUtils.isEmpty(artifactTypeStr)) {
                // derive the type from the artifact template
                if (artifactTemplateId == null) {
                    return Response.status(Status.NOT_ACCEPTABLE).entity(
                            "No artifactTemplate and no artifactType provided. Deriving the artifactType is not possible.")
                            .build();
                }
                artifactTemplateResource = new ArtifactTemplateResource(artifactTemplateId);
                artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class,
                        artifactTemplateResource.getType());
            } else {
                // artifactTypeStr is directly given, use that
                artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTypeStr);
            }
        } else {
            // do the artifact template auto creation magic

            if (StringUtils.isEmpty(artifactTypeStr)) {
                return Response.status(Status.BAD_REQUEST)
                        .entity("Artifact template auto creation requested, but no artifact type supplied.")
                        .build();
            }

            // we assume that the type points to a valid artifact type
            artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTypeStr);

            if (StringUtils.isEmpty(artifactTemplateName) || StringUtils.isEmpty(artifactTemplateNS)) {
                // no explicit name provided
                // we use the artifactNameStr as prefix for the
                // artifact template name

                // we create a new artifact template in the namespace of the parent
                // element
                Namespace namespace = this.resWithNamespace.getNamespace();

                artifactTemplateId = new ArtifactTemplateId(namespace,
                        new XMLId(artifactNameStr + "artifactTemplate", false));
            } else {
                QName artifactTemplateQName = new QName(artifactTemplateNS, artifactTemplateName);
                artifactTemplateId = new ArtifactTemplateId(artifactTemplateQName);
            }
            ResourceCreationResult creationResult = BackendUtils.create(artifactTemplateId);
            if (!creationResult.isSuccess()) {
                // something went wrong. skip
                return creationResult.getResponse();
            }

            // associate the type to the created artifact template
            artifactTemplateResource = new ArtifactTemplateResource(artifactTemplateId);
            // set the type. The resource is automatically persisted inside
            artifactTemplateResource.setType(artifactTypeStr);
        }

        // variable artifactTypeId is set
        // variable artifactTemplateId is not null if artifactTemplate has been generated

        // we have to generate the DA/IA resource now
        // Doing it here instead of doing it at the subclasses is dirty on the
        // one hand, but quicker to implement on the other hand

        // Create the artifact itself

        ArtifactT resultingArtifact;

        if (this instanceof ImplementationArtifactsResource) {
            ImplementationArtifact a = new ImplementationArtifact();
            // Winery internal id is the name of the artifact:
            // store the name
            a.setName(artifactNameStr);
            a.setInterfaceName(interfaceNameStr);
            a.setOperationName(operationNameStr);
            assert (artifactTypeId != null);
            a.setArtifactType(artifactTypeId.getQName());
            if (artifactTemplateId != null) {
                a.setArtifactRef(artifactTemplateId.getQName());
            }
            if (doc != null) {
                // the content has been checked for validity at the beginning of the method.
                // If this point in the code is reached, the XML has been parsed into doc
                // just copy over the dom node. Hopefully, that works...
                a.getAny().add(doc.getDocumentElement());
            }

            this.list.add((ArtifactT) a);
            resultingArtifact = (ArtifactT) a;
        } else {
            // for comments see other branch

            TDeploymentArtifact a = new TDeploymentArtifact();
            a.setName(artifactNameStr);
            assert (artifactTypeId != null);
            a.setArtifactType(artifactTypeId.getQName());
            if (artifactTemplateId != null) {
                a.setArtifactRef(artifactTemplateId.getQName());
            }
            if (doc != null) {
                a.getAny().add(doc.getDocumentElement());
            }

            this.list.add((ArtifactT) a);
            resultingArtifact = (ArtifactT) a;
        }

        Response persistResponse = BackendUtils.persist(super.res);
        // TODO: check for error and in case one found return that

        if (StringUtils.isEmpty(autoGenerateIA)) {
            // no IA generation
            // we include an XML for the data table

            String implOrDeplArtifactXML = Utils.getXMLAsString(resultingArtifact);

            return Response.created(Utils.createURI(Util.URLencode(artifactNameStr))).entity(implOrDeplArtifactXML)
                    .build();
        } else {
            // after everything was created, we fire up the artifact generation
            return this.generateImplementationArtifact(interfaceNameStr, javapackage, uriInfo, artifactTemplateId,
                    artifactTemplateResource);
        }
    }

    /**
     * Generates a unique and valid name to be used for the generated maven
     * project name, java project name, class name, port type name.
     */
    private String generateName(NodeTypeId nodeTypeId, String interfaceName) {
        String name = Util.namespaceToJavaPackage(nodeTypeId.getNamespace().getDecoded());
        name += Util.FORBIDDEN_CHARACTER_REPLACEMENT;

        // Winery already ensures that this is a valid NCName
        // getName() returns the id of the nodeType: A nodeType carries the "id" attribute only (and no name attribute)
        name += nodeTypeId.getXmlId().getDecoded();

        // Two separators to distinguish node type and interface part
        name += Util.FORBIDDEN_CHARACTER_REPLACEMENT;
        name += Util.FORBIDDEN_CHARACTER_REPLACEMENT;
        name += Util.namespaceToJavaPackage(interfaceName);

        // In addition we must replace '.', because Java class names must not
        // contain dots, but for Winery they are fine.
        return name.replace(".", Util.FORBIDDEN_CHARACTER_REPLACEMENT);
    }

    /**
     * Generates the implementation artifact using the implementation artifact
     * generator. Also sets the proeprties according to the requirements of
     * OpenTOSCA.
     * 
     * @param interfaceNameStr
     * @param javapackage
     * @param uriInfo
     * @param artifactTemplateId
     * @param artifactTemplateResource the resource associated with the
     *            artifactTempalteId. If null, the object is created in this
     *            method
     * 
     * @return {@inheritDoc}
     */
    private Response generateImplementationArtifact(String interfaceNameStr, String javapackage, UriInfo uriInfo,
            ArtifactTemplateId artifactTemplateId, ArtifactTemplateResource artifactTemplateResource) {
        TInterface iface;

        assert (this instanceof ImplementationArtifactsResource);
        IHasTypeReference typeRes = (EntityTypeImplementationResource) this.res;
        QName type = typeRes.getType();
        TOSCAComponentId typeId;
        TNodeType nodeType = null;
        if (typeRes instanceof NodeTypeImplementationResource) {
            // TODO: refactor: This is more a model/repo utilities thing than something which should happen here...

            typeId = new NodeTypeId(type);
            NodeTypeResource ntRes = (NodeTypeResource) AbstractComponentsResource
                    .getComponentInstaceResource(typeId);

            // required for IA Generation
            nodeType = ntRes.getNodeType();

            List<TInterface> interfaces = nodeType.getInterfaces().getInterface();
            Iterator<TInterface> it = interfaces.iterator();
            do {
                iface = it.next();
                if (iface.getName().equals(interfaceNameStr)) {
                    break;
                }
            } while (it.hasNext());
            // iface now contains the right interface
        } else {
            assert (typeRes instanceof RelationshipTypeImplementationResource);
            return Response.serverError()
                    .entity("IA creation for relation ship type implementations not yet possible").build();
        }

        Path workingDir;
        try {
            workingDir = Files.createTempDirectory("winery");
        } catch (IOException e2) {
            GenericArtifactsResource.logger.debug("Could not create temporary directory", e2);
            return Response.serverError().entity("Could not create temporary directory").build();
        }

        URI artifactTemplateFilesUri = uriInfo.getBaseUri().resolve(Utils.getAbsoluteURL(artifactTemplateId))
                .resolve("files/");
        URL artifactTemplateFilesUrl;
        try {
            artifactTemplateFilesUrl = artifactTemplateFilesUri.toURL();
        } catch (MalformedURLException e2) {
            GenericArtifactsResource.logger.debug("Could not convert URI to URL", e2);
            return Response.serverError().entity("Could not convert URI to URL").build();
        }

        String name = this.generateName((NodeTypeId) typeId, interfaceNameStr);
        Generator gen = new Generator(iface, javapackage, artifactTemplateFilesUrl, name, workingDir.toFile());
        File zipFile = gen.generateProject();
        if (zipFile == null) {
            return Response.serverError().entity("IA generator failed").build();
        }

        // store it
        // TODO: refactor: this is more a RepositoryUtils thing than a special thing here; see also importFile at CSARImporter

        ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId(artifactTemplateId);
        RepositoryFileReference fref = new RepositoryFileReference(fileDir, zipFile.getName().toString());
        try (InputStream is = Files.newInputStream(zipFile.toPath());
                BufferedInputStream bis = new BufferedInputStream(is)) {
            String mediaType = Utils.getMimeType(bis, zipFile.getName());
            // TODO: do the catch thing as in CSARImporter

            Repository.INSTANCE.putContentToFile(fref, bis, MediaType.valueOf(mediaType));
        } catch (IOException e1) {
            throw new IllegalStateException("Could not import generated files", e1);
        }

        // cleanup dir
        try {
            FileUtils.forceDelete(workingDir);
        } catch (IOException e) {
            GenericArtifactsResource.logger.debug("Could not delete working directory", e);
        }

        // store the properties in the artifact template
        if (artifactTemplateResource == null) {
            artifactTemplateResource = (ArtifactTemplateResource) AbstractComponentsResource
                    .getComponentInstaceResource(artifactTemplateId);
        }
        this.storeProperties(artifactTemplateResource, typeId, name);

        URI url = uriInfo.getBaseUri().resolve(Utils.getAbsoluteURL(fref));
        return Response.created(url).build();
    }

    private final String NS_OPENTOSCA_WAR_TYPE = "http://www.uni-stuttgart.de/opentosca";

    private void storeProperties(ArtifactTemplateResource artifactTemplateResource, TOSCAComponentId typeId,
            String name) {
        // We generate the properties by hand instead of using JAX-B as using JAX-B causes issues at org.eclipse.winery.common.ModelUtilities.getPropertiesKV(TEntityTemplate):
        // getAny() does not always return "w3c.dom.element" anymore

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder;
        try {
            builder = dbf.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            GenericArtifactsResource.logger.error(e.getMessage(), e);
            return;
        }
        Document doc = builder.newDocument();
        Element root = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "WSProperties");
        doc.appendChild(root);

        Element element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "ServiceEndpoint");
        Text text = doc.createTextNode("/services/" + name + "Port");
        element.appendChild(text);
        root.appendChild(element);

        element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "PortType");
        text = doc.createTextNode("{" + typeId.getNamespace().getDecoded() + "}" + name);
        element.appendChild(text);
        root.appendChild(element);

        element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "InvocationType");
        text = doc.createTextNode("SOAP/HTTP");
        element.appendChild(text);
        root.appendChild(element);

        Properties properties = new Properties();
        properties.setAny(root);
        PropertiesResource propertiesResource = artifactTemplateResource.getPropertiesResource();
        propertiesResource.setProperties(properties);
    }

    @Override
    public Viewable getHTML() {
        return new Viewable("/jsp/artifacts/artifacts.jsp", this);
    }

    /**
     * Required for artifacts.jsp
     * 
     * @return list of known artifact types.
     */
    public List<QName> getAllArtifactTypes() {
        SortedSet<ArtifactTypeId> allArtifactTypes = Repository.INSTANCE
                .getAllTOSCAComponentIds(ArtifactTypeId.class);
        List<QName> res = new ArrayList<QName>(allArtifactTypes.size());
        for (ArtifactTypeId id : allArtifactTypes) {
            res.add(id.getQName());
        }
        return res;
    }

    /**
     * Required for artifacts.jsp
     * 
     * @return list of all contained artifacts.
     */
    public abstract Collection<ArtifactResource> getAllArtifactResources();

    /**
     * Required by artifact.jsp to decide whether to display
     * "Deployment Artifact" or "Implementation Artifact"
     */
    public boolean getIsDeploymentArtifacts() {
        boolean res = (this instanceof DeploymentArtifactsResource);
        return res;
    }

    /**
     * required by artifacts.jsp
     */
    public String getNamespace() {
        return this.resWithNamespace.getNamespace().getDecoded();
    }

    /**
     * For saving resources, an AbstractComponentInstanceResource is required.
     * DAs may be attached to a node template, which is not an
     * AbstractComponentInstanceResource, but its grandparent resource
     * ServiceTemplate is
     * 
     * @param res the resource to determine the the
     *            AbstractComponentInstanceResource for
     * @return the AbstractComponentInstanceResource where the given res is
     *         contained in
     */
    public static AbstractComponentInstanceResource getAbstractComponentInstanceResource(
            INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) {
        final AbstractComponentInstanceResource r;
        if (res instanceof NodeTemplateResource) {
            r = ((NodeTemplateResource) res).getServiceTemplateResource();
        } else {
            // quick hack: the resource has to be an abstract component instance
            r = (AbstractComponentInstanceResource) res;
        }
        return r;
    }
}