Package org.drools.guvnor.server.jaxrs

Source Code of org.drools.guvnor.server.jaxrs.PackageResource

/*
* Copyright 2011 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.drools.guvnor.server.jaxrs;

import com.google.gwt.user.client.rpc.SerializationException;
import java.io.IOException;
import org.drools.guvnor.client.common.AssetFormats;
import org.drools.guvnor.client.rpc.BuilderResult;
import org.drools.guvnor.client.rpc.BuilderResultLine;
import org.drools.guvnor.server.builder.ModuleAssembler;
import org.drools.guvnor.server.builder.ModuleAssemblerManager;
import org.drools.guvnor.server.cache.RuleBaseCache;
import org.drools.guvnor.server.jaxrs.jaxb.*;
import org.drools.guvnor.server.jaxrs.jaxb.Package;
import org.drools.guvnor.server.jaxrs.providers.atom.Entry;
import org.drools.guvnor.server.jaxrs.providers.atom.Feed;
import org.drools.guvnor.server.jaxrs.providers.atom.Link;
import org.drools.repository.*;
import org.jboss.resteasy.annotations.GZIP;
import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
import org.jboss.seam.security.annotations.LoggedIn;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.xml.bind.JAXBException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.drools.guvnor.server.contenthandler.ContentHandler;
import org.drools.guvnor.server.contenthandler.ContentManager;
import org.drools.guvnor.server.contenthandler.ICanHasAttachment;

import static org.drools.guvnor.server.jaxrs.Translator.*;

/**
* Contract:  Package names and asset names within a package namespace
* must be unique.  REST API avoids use of asset UUIDs through this
* contract.
* Exception handling: At the moment we catch all exceptions thrown from underlying repository and wrap
* them with WebApplicationException. We need to set detailed exception message on WebApplicationException.
* We also need to set HTTP error code on WebApplicationException if we want a HTTP response code other
* than 500 (Internal Server Error).
* In the future, we may use ExceptionMapper provider to map a checked or runtime exception to a
* HTTP response. Note, if there are no mappers found for custom exceptions, they will be propagated
* (wrapped in ServletException) to the underlying container as required by the spec.
*/
@Path("/packages")
@RequestScoped
@Named
@LoggedIn
@GZIP
public class PackageResource extends Resource {
    private HttpHeaders headers;

    @Context
    public void setHttpHeaders(HttpHeaders theHeaders) {
        headers = theHeaders;
    }

    @GET
    @Produces(MediaType.APPLICATION_ATOM_XML)
    public Feed getPackagesAsFeed() {
        Feed f = new Feed();
        f.setTitle("Packages");
        f.setBase(uriInfo.getBaseUriBuilder().path("packages").build());
        ModuleIterator iter = rulesRepository.listModules();
        while (iter.hasNext()) {
            ModuleItem item = iter.next();
            Entry e = new Entry();
            e.setTitle(item.getName());
            Link l = new Link();
            l.setHref(uriInfo.getBaseUriBuilder()
                    .path("packages/{itemName}")
                    .build(item.getName()));
            e.getLinks().add(l);
            f.getEntries().add(e);
        }

        return f;
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Collection<Package> getPackagesAsJAXB() {
        List<Package> ret = new ArrayList<Package>();
        ModuleIterator iter = rulesRepository.listModules();
        while (iter.hasNext()) {
            //REVIST: Do not return detailed package info here. Package title and link should be enough.
            ret.add(toPackage(iter.next(), uriInfo));
        }
        return ret;
    }

    @POST
    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
    @Produces(MediaType.APPLICATION_ATOM_XML)
    @GuvnorDecorators
    public Entry createPackageFromDRLAndReturnAsEntry(InputStream is, @Context UriInfo uriInfo) {
        /*
         * Passes the DRL to the FileManagerService and has it import the asset as
         * a package
         */
        try {
            String packageName = fileManagerService.importClassicDRL(is, null);
            //NOTE: no need to call packageItem.updateBinaryUpToDate(false) as this done by importClassicDRL
            return toPackageEntryAbdera(rulesRepository.loadModule(packageName), uriInfo);
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @POST
    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Package createPackageFromDRLAndReturnAsJaxB(InputStream is) {
        /*
         * Passes the DRL to the FileManagerService and has it import the asset as
         * a package
         */
        try {
            String packageName = fileManagerService.importClassicDRL(is, null);
            //NOTE: no need to call packageItem.updateBinaryUpToDate(false) as this done by importClassicDRL
            return toPackage(rulesRepository.loadModule(packageName), uriInfo);
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @POST
    @Consumes(MediaType.APPLICATION_ATOM_XML)
    @Produces(MediaType.APPLICATION_ATOM_XML)
    @GuvnorDecorators
    public Entry createPackageFromAtom(Entry entry) {
        try {
            String checkinComment = "Initial";
            entry.getAnyOtherElement();

            AtomPackageMetadata metaData = entry.getAnyOtherJAXBObject(AtomPackageMetadata.class);
            if (metaData != null) {
                checkinComment = metaData.getCheckinComment();
            }
            ModuleItem packageItem = rulesRepository.createModule(entry.getTitle(), entry.getSummary(), ModuleItem.MODULE_FORMAT, null, checkinComment);
            //NOTE: no need to call packageItem.updateBinaryUpToDate(false) for a newly created module as the default value of BinaryUpToDate is false
            return toPackageEntryAbdera(packageItem, uriInfo);
        } catch (JAXBException e) {
            throw new WebApplicationException(e);
        } catch (RuntimeException e) {
            //catch RulesRepositoryException and other exceptions. For example when the package already exists.
            throw new WebApplicationException(e);
        }
    }

    @POST
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Package createPackageFromJAXB(Package p) {
        try {
            String checkinComment = "Initial";
            if(p.getMetadata() != null && p.getMetadata().getCheckinComment() != null) {
                checkinComment = p.getMetadata().getCheckinComment();
            }
           
            ModuleItem packageItem = rulesRepository.createModule(p.getTitle(), p.getDescription(), ModuleItem.MODULE_FORMAT, null, checkinComment);
            //NOTE: no need to call packageItem.updateBinaryUpToDate(false) for a newly created module as the default value of BinaryUpToDate is false
            return toPackage(packageItem, uriInfo);
        } catch (RuntimeException e) {
            //catch RulesRepositoryException and other exceptions. For example when the package already exists.
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}")
    @Produces(MediaType.APPLICATION_ATOM_XML)
    @GuvnorDecorators
    public Entry getPackageAsEntry(@PathParam("packageName") String packageName) {
        if (!rulesRepository.containsModule(packageName)) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                    .entity("Package [" + packageName + "] does not exist").build());
        }
        try {
            ModuleItem packageItem = rulesRepository.loadModule(packageName);
            return toPackageEntryAbdera(packageItem, uriInfo);
        } catch (RuntimeException e) {
            //catch RulesRepositoryException and other exceptions. For example when the package does not exists.
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}")
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Package getPackageAsJAXB(@PathParam("packageName") String packageName) {
        if (!rulesRepository.containsModule(packageName)) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                    .entity("Package [" + packageName + "] does not exist").build());
        }
        try {
            ModuleItem packageItem = rulesRepository.loadModule(packageName);
            return toPackage(packageItem, uriInfo);
        } catch (RuntimeException e) {
            //catch RulesRepositoryException and other exceptions. For example when the package does not exists.
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}/source")
    @Produces(MediaType.TEXT_PLAIN)
    public Response getPackageSource(@PathParam("packageName") String packageName) {
        if (!rulesRepository.containsModule(packageName)) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                    .entity("Package [" + packageName + "] does not exist").build());
        }
        try {
            ModuleItem moduleItem = rulesRepository.loadModule(packageName);
            ModuleAssembler moduleAssembler = ModuleAssemblerManager.getModuleAssembler(moduleItem.getFormat(), moduleItem, null);
            String drl = moduleAssembler.getCompiledSource();
            return Response.ok(drl).header("Content-Disposition", "attachment; filename=" + packageName).
                    header("Last-Modified", createDateFormat().format(this.convertToGmt(moduleItem.getLastModified()).getTime())).build();
        } catch (RuntimeException e) {
            //catch RulesRepositoryException and other exceptions. For example when the package does not exists.
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}/binary")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getPackageBinary(@PathParam("packageName") String packageName) throws SerializationException {
        if (!rulesRepository.containsModule(packageName)) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                    .entity("Package [" + packageName + "] does not exist").build());
        }
        try {
            ModuleItem p = compileModuleIfNeeded(packageName);
            byte[] result = p.getCompiledBinaryBytes();
            ModuleAssembler moduleAssembler = ModuleAssemblerManager.getModuleAssembler(p.getFormat(), p, null);
            String fileName = packageName + "." + moduleAssembler.getBinaryExtension();
            return Response.ok(result).header("Content-Disposition", "attachment; filename=" + fileName).
                    header("Last-Modified", createDateFormat().format(this.convertToGmt(p.getLastModified()).getTime())).build();
        } catch (RuntimeException e) {
            //catch RulesRepositoryException and other exceptions. For example when the package does not exists.
            throw new WebApplicationException(e);
        }
    }

    private ModuleItem compileModuleIfNeeded(String packageName) throws SerializationException {
        ModuleItem p = rulesRepository.loadModule(packageName);
        if (p.isBinaryUpToDate()) {
            return p;
        } else {
            BuilderResult builderResult = repositoryPackageService.buildPackage(p.getUUID(), true);
            if (builderResult != null && !builderResult.getLines().isEmpty()) {
                StringBuilder errs = new StringBuilder();
                errs.append("Unable to build package name [").append(packageName).append("]\n");
                for (BuilderResultLine resultLine : builderResult.getLines()) {
                    errs.append(resultLine.toString()).append("\n");
                }
                throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(errs.toString()).build());
            }
            return rulesRepository.loadModule(packageName);
        }
    }


    @GET
    @Path("{packageName}/versions")
    @Produces(MediaType.APPLICATION_ATOM_XML)
    public Feed getPackageVersionsAsFeed(@PathParam("packageName") String packageName) throws SerializationException {
        if (!rulesRepository.containsModule(packageName)) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                    .entity("Package [" + packageName + "] does not exist").build());
        }
        ModuleItem p = rulesRepository.loadModule(packageName);

        Feed f = new Feed();
        f.setTitle("Version history of " + p.getName());
        f.setBase(uriInfo.getBaseUriBuilder().path("packages").build());
        ModuleHistoryIterator it = p.getHistory();

        while (it.hasNext()) {
            try {
                ModuleItem historicalPackage = it.next();
                if (historicalPackage.getVersionNumber() != 0) {
                    Entry e = new Entry();
                    e.setTitle(Long.toString(historicalPackage
                            .getVersionNumber()));
                    e.setUpdated(historicalPackage.getLastModified().getTime());
                    Link l = new Link();
                    l.setHref(uriInfo
                            .getBaseUriBuilder()
                            .path("packages/{packageName}/versions/{versionNumber}")
                            .build(p.getName(), Long.toString(historicalPackage.getVersionNumber())));
                    e.getLinks().add(l);
                    f.getEntries().add(e);
                }
            } catch (RuntimeException e) {
                throw new WebApplicationException(e);
            }
        }

        return f;
    }

    @GET
    @Path("{packageName}/versions/{versionNumber}")
    @Produces(MediaType.APPLICATION_ATOM_XML)
    @GuvnorDecorators
    public Entry getHistoricalPackageAsEntry(@PathParam("packageName") String packageName,
                                             @PathParam("versionNumber") long versionNumber) throws SerializationException {
        return toPackageEntryAbdera(rulesRepository.loadModule(packageName, versionNumber), uriInfo);
    }

    @GET
    @Path("{packageName}/versions/{versionNumber}/source")
    @Produces(MediaType.TEXT_PLAIN)
    public Response getHistoricalPackageSource(@PathParam("packageName") String packageName,
                                               @PathParam("versionNumber") long versionNumber) {
        ModuleItem item = rulesRepository.loadModule(packageName, versionNumber);
        ModuleAssembler moduleAssembler = ModuleAssemblerManager.getModuleAssembler(item.getFormat(), item, null);
        String drl = moduleAssembler.getCompiledSource();
        return Response.ok(drl).header("Content-Disposition", "attachment; filename=" + packageName).
                    header("Last-Modified", createDateFormat().format(this.convertToGmt(item.getLastModified()).getTime())).build();
    }

    @GET
    @Path("{packageName}/versions/{versionNumber}/binary")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getHistoricalPackageBinary(@PathParam("packageName") String packageName,
                                               @PathParam("versionNumber") long versionNumber) throws SerializationException {
        ModuleItem p = rulesRepository.loadModule(packageName, versionNumber);
        byte[] result = p.getCompiledBinaryBytes();
       
        //REVISIT: https://issues.jboss.org/browse/GUVNOR-1232: Force a package rebuild before every package check in operation.
        if (result != null) {
            ModuleAssembler moduleAssembler = ModuleAssemblerManager.getModuleAssembler(p.getFormat(), p, null);
            String fileName = packageName + "." + moduleAssembler.getBinaryExtension();
            return Response.ok(result).header("Content-Disposition", "attachment; filename=" + fileName).
                    header("Last-Modified", createDateFormat().format(this.convertToGmt(p.getLastModified()).getTime())).build();
        } else {
            return Response.status(500).entity("This package version has no compiled binary").type("text/plain").build();
        }
    }

    @PUT
    @Path("{packageName}")
    @Consumes(MediaType.APPLICATION_ATOM_XML)
    public void updatePackageFromAtom(@PathParam("packageName") String packageName, Entry entry) {
       try {
            ModuleItem existingModuleItem = rulesRepository.loadModule(packageName);
           
            //Rename:
            if (!existingModuleItem.getTitle().equalsIgnoreCase(entry.getTitle())) {
                rulesRepository.renameModule(existingModuleItem.getUUID(), entry.getTitle());
            }

            if (entry.getSummary() != null) {
                existingModuleItem.updateDescription(entry.getSummary());
            }
           
            // TODO: support LastContributor
            if (!entry.getAuthors().isEmpty()) {
            }

            String checkinComment = "";

           AtomPackageMetadata packageMetadata = entry.getAnyOtherJAXBObject(AtomPackageMetadata.class);
           if ( packageMetadata != null ) {
               existingModuleItem.archiveItem(packageMetadata.isArchived());
               checkinComment = packageMetadata.getCheckinComment();
           }

            existingModuleItem.updateBinaryUpToDate(false);
            existingModuleItem.checkin(checkinComment);
            rulesRepository.save();
       } catch (JAXBException e) {
           throw new WebApplicationException(e);
       } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @PUT
    @Path("{packageName}")
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public void updatePackageFromJAXB(@PathParam("packageName") String packageName, Package module) {
        try {
            ModuleItem existingModuleItem = rulesRepository.loadModule(packageName);
           
            //Rename:
            if (!existingModuleItem.getTitle().equalsIgnoreCase(module.getTitle())) {
                rulesRepository.renameModule(existingModuleItem.getUUID(), module.getTitle());
            }
           
            existingModuleItem.updateDescription(module.getDescription());
           
            /* TODO: add more updates to package item from JSON */
            existingModuleItem.updateBinaryUpToDate(false);
            existingModuleItem.checkin(module.getMetadata().getCheckinComment());
            rulesRepository.save();
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @DELETE
    @Path("{packageName}")
    public void deletePackage(@PathParam("packageName") String packageName) {
        try {
            //Throws RulesRepositoryException if the package does not exist
            ModuleItem p = rulesRepository.loadModule(packageName);
            repositoryPackageService.removeModule(p.getUUID());
        } catch (RuntimeException e) {
            // catch RulesRepositoryException and other exceptions.
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}/assets")
    @Produces(MediaType.APPLICATION_ATOM_XML)
    public Feed getAssetsAsAtom(
            @PathParam("packageName") String packageName,
            @QueryParam("format") List<String> formats) {
        try {
            Feed feed = new Feed();
            ModuleItem p = rulesRepository.loadModule(packageName);
            feed.setTitle(p.getTitle() + "-asset-feed");
           
            Iterator<AssetItem> iter = null;
           
            if (formats.isEmpty()){
                //no format specified? Return all assets
                iter = p.getAssets();
            }else{
                //if the format is specified, return only the assets of
                //the specified formats.
                iter = p.listAssetsByFormat(formats);
            }
           
            while (iter.hasNext())
                feed.getEntries().add(toAssetEntryAbdera(iter.next(), uriInfo));
            return feed;
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }
   
    @GET
    @Path("{packageName}/assets")
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Collection<Asset> getAssetsAsJAXB(
            @PathParam("packageName") String packageName,
            @QueryParam("format") List<String> formats) {
        try {
            List<Asset> ret = new ArrayList<Asset>();
            ModuleItem p = rulesRepository.loadModule(packageName);
           
            Iterator<AssetItem> iter = null;
           
            if (formats.isEmpty()){
                //no format specified? Return all assets
                iter = p.getAssets();
            }else{
                //if the format is specified, return only the assets of
                //the specified formats.
                iter = p.listAssetsByFormat(formats);
            }
           
            while (iter.hasNext()) {
                ret.add(toAsset(iter.next(), uriInfo));
            }
            return ret;
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}/assets/{assetName}")
    @Produces(MediaType.APPLICATION_ATOM_XML)
    @GuvnorDecorators
    public Entry getAssetAsAtom(@PathParam("packageName") String packageName, @PathParam("assetName") String assetName) {
        if (!assetExists(packageName, assetName)) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                    .entity("Asset [" + assetName + "] of package [" + packageName + "] does not exist").build());
        }
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem asset = rulesRepository.loadModule(packageName).loadAsset(assetName);
            return toAssetEntryAbdera(asset, uriInfo);
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}/assets/{assetName}")
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})

    public Asset getAssetAsJaxB(@PathParam("packageName") String packageName, @PathParam("assetName") String assetName) {
        if (!assetExists(packageName, assetName)) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                    .entity("Asset [" + assetName + "] of package [" + packageName + "] does not exist").build());
        }
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem asset = rulesRepository.loadModule(packageName).loadAsset(assetName);
            return toAsset(asset, uriInfo);
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}/assets/{assetName}/binary")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getAssetBinary(@PathParam("packageName") String packageName, @PathParam("assetName") String assetName) {
        if (!assetExists(packageName, assetName)) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                    .entity("Asset [" + assetName + "] of package [" + packageName + "] does not exist").build());
        }
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem asset = rulesRepository.loadModule(packageName).loadAsset(assetName);
            String fileName = null;
            String binaryContentAttachmentFileName = asset.getBinaryContentAttachmentFileName();                   
            //Note the file extension name may not be same as asset format name in some cases.
            if(binaryContentAttachmentFileName !=null && !"".equals(binaryContentAttachmentFileName)) {
                fileName = binaryContentAttachmentFileName;
            } else {
                fileName = asset.getName() + "." + asset.getFormat();
            }

            return Response.ok(asset.getBinaryContentAttachment()).header("Content-Disposition", "attachment; filename=" + fileName).build();
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}/assets/{assetName}/source")
    @Produces(MediaType.TEXT_PLAIN)
    public String getAssetSource(@PathParam("packageName") String packageName, @PathParam("assetName") String assetName) {
        if (!assetExists(packageName, assetName)) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                    .entity("Asset [" + assetName + "] of package [" + packageName + "] does not exist").build());
        }
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem asset = rulesRepository.loadModule(packageName).loadAsset(assetName);
            return asset.getContent();
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }
    @GET
    @Path("{packageName}/snapshots")
    @Produces({MediaType.APPLICATION_ATOM_XML,MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
    public Snapshots getPackageSnapshot(
            @PathParam("packageName") String packageName) {
        try {
            Snapshots snapshots = new Snapshots();
            snapshots.setPackageName(packageName);
            String[] theList = rulesRepository.listModuleSnapshots(packageName)
            snapshots.setListNames(theList);
            return snapshots;
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }
    @POST
    @Path("{packageName}/assets")
    @Consumes(MediaType.APPLICATION_ATOM_XML)
    @Produces(MediaType.APPLICATION_ATOM_XML)
    @GuvnorDecorators
    public Entry createAssetFromAtom(@PathParam("packageName") String packageName, Entry entry) {
        try {
            String format = null;
            String[] categories = null;
            AtomAssetMetadata assetMetadata = entry.getAnyOtherJAXBObject(AtomAssetMetadata.class);
            categories = assetMetadata.getCategories();

            AssetItem ai = rulesRepository.loadModule(packageName).addAsset(entry.getTitle(), entry.getSummary(), null, assetMetadata.getFormat());

            if (categories != null) {
                ai.updateCategoryList(categories);
            }
            if (assetMetadata!= null && assetMetadata.getState() != null) {
                ai.updateState(assetMetadata.getState());
            }
            //The categories are not saved by addAsset(). Need to force it here.
            ai.getModule().updateBinaryUpToDate(false);
            rulesRepository.save();

            return toAssetEntryAbdera(ai, uriInfo);
        } catch (JAXBException e) {
            throw new WebApplicationException(e);
        } catch (RuntimeException e) {
            //catch RulesRepositoryException and other exceptions. For example when the package already exists.
            throw new WebApplicationException(e);
        }
    }

    @POST
    @Path("{packageName}/assets")
    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
    @Produces(MediaType.APPLICATION_ATOM_XML)
    @GuvnorDecorators
    public Entry createAssetFromBinary(@PathParam("packageName") String packageName, InputStream is) {
        try {
            String assetName = getHttpHeader(headers, "slug");
            if (assetName == null) {
                throw new WebApplicationException(Response.status(500).entity("Slug header is missing").build());
            } else {
                try {
                    assetName = URLDecoder.decode(assetName, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    throw new IllegalStateException("This server does not support UTF-8 encoding.", e);
                }
            }
            String fileName = null;
            String extension = null;
            if (assetName.lastIndexOf(".") != -1) {
                fileName = assetName.substring(0, assetName.lastIndexOf("."));               
                extension = assetName.substring(assetName.lastIndexOf(".")+1);
            } else {
                fileName = assetName;               
            }           
           
            AssetItem ai = rulesRepository.loadModule(packageName).addAsset(fileName, "");
            ai.checkout();
            ai.updateBinaryContentAttachmentFileName(fileName);
           
            //Asset format and asset file extension are 2 different things. We simply do not have the asset type information available when the
            //asset is created from binary. The asset format needs to be filled by a following update operation.
            //But we can do our best to guess the format here, i.e., assume the format is equal to the extension type. User can always update
            //the format later on
            if (extension != null) {
                ai.updateFormat(extension);
            }
            ai.updateBinaryContentAttachment(is);
            ai.getModule().updateBinaryUpToDate(false);
            ai.updateValid(assetValidator.validate(ai));
            ai.checkin("update binary");
            ContentHandler handler = ContentManager.getHandler(ai.getFormat());
            if (handler instanceof ICanHasAttachment) {
                try {
                    ((ICanHasAttachment) handler).onAttachmentAdded(ai);
                } catch (IOException ex) {
                    Logger.getLogger(PackageResource.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            rulesRepository.save();
            return toAssetEntryAbdera(ai, uriInfo);
        } catch (RuntimeException e) {
            //catch RulesRepositoryException and other exceptions. For example when the package already exists.
            throw new WebApplicationException(e);
        }
    }

    @PUT
    @Path("{packageName}/assets/{assetName}")
    @Consumes(MediaType.APPLICATION_ATOM_XML)
    public void updateAssetFromAtom(@PathParam("packageName") String packageName, @PathParam("assetName") String assetName, Entry assetEntry) {
        try {
            AtomAssetMetadata assetMetadata = assetEntry.getAnyOtherJAXBObject(AtomAssetMetadata.class);

            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem ai = rulesRepository.loadModule(packageName).loadAsset(assetName);
            //Update asset
            ai.checkout();
            ai.updateTitle(assetEntry.getTitle());
            ai.updateDescription(assetEntry.getSummary());
            if (assetMetadata.getFormat() != null) {
                ai.updateFormat(assetMetadata.getFormat());
            }
           
            //REVISIT: What if the client really wants to set content to ""?
            if (assetEntry.getContent().getText() != null && !"".equals(assetEntry.getContent().getText())) {
                ai.updateContent(assetEntry.getContent().getText());
            }
            if (assetMetadata.getCategories() != null && assetMetadata.getCategories().length > 0) {
                ai.updateCategoryList(assetMetadata.getCategories());
            }
            if (assetMetadata.getState() != null) {
                ai.updateState(assetMetadata.getState());
            }
            ai.updateDisabled(assetMetadata.getDisabled());
            ai.updateValid(assetValidator.validate(ai));
            if (AssetFormats.affectsBinaryUpToDate(ai.getFormat())) {
                ModuleItem pkg = ai.getModule();
                pkg.updateBinaryUpToDate(false);
                RuleBaseCache.getInstance().remove(pkg.getUUID());
            }
            ai.checkin("Check-in (summary): " + assetEntry.getSummary());
            rulesRepository.save();
        } catch (JAXBException e) {
            throw new WebApplicationException(e);
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @PUT
    @Path("{packageName}/assets/{assetName}")
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public void updateAssetFromJAXB(
            @PathParam("packageName") String packageName,
            @PathParam("assetName") String assetName, Asset asset) {
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem ai = rulesRepository.loadModule(packageName).loadAsset(assetName);
            /* Update asset */
            ai.checkout();
            ai.updateTitle(asset.getTitle());
            ai.updateDescription(asset.getDescription());
            ai.updateValid(assetValidator.validate(ai));
            if (asset.getMetadata() != null){
                AssetMetadata assetMetadata = asset.getMetadata();
                if (assetMetadata.getState() != null) {
                    ai.updateState(assetMetadata.getState());
                }
                if (assetMetadata.getCategories()!= null){
                    ai.updateCategoryList(assetMetadata.getCategories());
                }             
                ai.updateDisabled(assetMetadata.isDisabled());
            }
            if (AssetFormats.affectsBinaryUpToDate(ai.getFormat())) {
                ModuleItem pkg = ai.getModule();
                pkg.updateBinaryUpToDate(false);
                RuleBaseCache.getInstance().remove(pkg.getUUID());
            }
            ai.checkin(asset.getMetadata().getCheckInComment());
            rulesRepository.save();
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @PUT
    @Path("{packageName}/assets/{assetName}/source")
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN})
    @Produces({MediaType.WILDCARD})
    public void updateAssetSource(@PathParam("packageName") String packageName, @PathParam("assetName") String assetName, String content) {
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem asset = rulesRepository.loadModule(packageName).loadAsset(assetName);
            asset.checkout();
            asset.updateContent(content);
            asset.updateValid(assetValidator.validate(asset));
            if (AssetFormats.affectsBinaryUpToDate(asset.getFormat())) {
                ModuleItem pkg = asset.getModule();
                pkg.updateBinaryUpToDate(false);
                RuleBaseCache.getInstance().remove(pkg.getUUID());
            }
            asset.checkin("Updated asset source from REST interface");
            rulesRepository.save();
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @PUT
    @Path("{packageName}/assets/{assetName}/binary")
    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
    @Produces(MediaType.WILDCARD)
    public void updateAssetBinary(@PathParam("packageName") String packageName, @PathParam("assetName") String assetName, InputStream is) {
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem asset = rulesRepository.loadModule(packageName).loadAsset(assetName);
            asset.checkout();
            asset.updateBinaryContentAttachment(is);
            asset.updateValid(assetValidator.validate(asset));
            if (AssetFormats.affectsBinaryUpToDate(asset.getFormat())) {
                ModuleItem pkg = asset.getModule();
                pkg.updateBinaryUpToDate(false);
                RuleBaseCache.getInstance().remove(pkg.getUUID());
            }
            asset.getModule().updateBinaryUpToDate(false);
            asset.checkin("Update binary");
            rulesRepository.save();
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @DELETE
    @Path("{packageName}/assets/{assetName}/")
    public void deleteAsset(@PathParam("packageName") String packageName,
                            @PathParam("assetName") String assetName) {
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem ai = rulesRepository.loadModule(packageName).loadAsset( assetName );
            ModuleItem module = ai.getModule();
            // assetService.archiveAsset(ai.getUUID());
            repositoryAssetService.removeAsset(ai.getUUID());
            module.updateBinaryUpToDate(false);
            rulesRepository.save();
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }
   
    @GET
    @Path("{packageName}/assets/{assetName}/versions")
    @Produces(MediaType.APPLICATION_ATOM_XML)
    public Feed getAssetVersionsAsFeed(@PathParam("packageName") String packageName,
                                       @PathParam("assetName") String assetName) {
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem asset = rulesRepository.loadModule(packageName).loadAsset(assetName);
           
            Feed f = new Feed();
            f.setTitle("Version history of " + asset.getName());

            URI base;
            if (asset.isHistoricalVersion()) {
                base = uriInfo.getBaseUriBuilder()
                        .path("packages/{packageName}/assets/{assetName}/versions/{versionNumber}")
                        .build(asset.getModuleName(), asset.getName(), Long.toString(asset.getVersionNumber()));
            } else {
                base = uriInfo.getBaseUriBuilder()
                        .path("packages/{packageName}/assets/{assetName}/versions")
                        .build(asset.getModuleName(), asset.getName());
            }
            f.setBase(base);
                       
            AssetHistoryIterator it = asset.getHistory();
            while (it.hasNext()) {
                AssetItem historicalAsset = it.next();
                if (historicalAsset.getVersionNumber() != 0) {
                    Entry e = new Entry();
                    e.setTitle(Long.toString(historicalAsset
                            .getVersionNumber()));
                    e.setUpdated(historicalAsset.getLastModified().getTime());
                    Link l = new Link();
                    l.setHref(uriInfo
                            .getBaseUriBuilder()
                            .path("packages/{packageName}/assets/{assetName}/versions/{versionNumber}")
                            .build(asset.getModuleName(), asset.getName(),
                                    Long.toString(historicalAsset.getVersionNumber())));
                    e.getLinks().add(l);
                    f.getEntries().add(e);
                }
            }
            return f;
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}/assets/{assetName}/versions/{versionNumber}")
    @Produces(MediaType.APPLICATION_ATOM_XML)
    @GuvnorDecorators
    public Entry getHistoricalAssetAsEntry(@PathParam("packageName") String packageName,
                                           @PathParam("assetName") String assetName,
                                           @PathParam("versionNumber") long versionNumber) {
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem asset = rulesRepository.loadModule(packageName).loadAsset(assetName, versionNumber);
            return toAssetEntryAbdera(asset, uriInfo);
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }  

    @GET
    @Path("{packageName}/assets/{assetName}/versions/{versionNumber}/source")
    @Produces(MediaType.TEXT_PLAIN)
    public String getHistoricalAssetSource(@PathParam("packageName") String packageName,
                                           @PathParam("assetName") String assetName,
                                           @PathParam("versionNumber") long versionNumber) {
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem asset = rulesRepository.loadModule(packageName).loadAsset(assetName, versionNumber);
            return asset.getContent();
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }

    @GET
    @Path("{packageName}/assets/{assetName}/versions/{versionNumber}/binary")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getHistoricalAssetBinary(@PathParam("packageName") String packageName,
                                             @PathParam("assetName") String assetName,
                                             @PathParam("versionNumber") long versionNumber) {
        try {
            //Throws RulesRepositoryException if the package or asset does not exist
            AssetItem asset = rulesRepository.loadModule(packageName).loadAsset(assetName, versionNumber);
            String fileName = null;
            String binaryContentAttachmentFileName = asset.getBinaryContentAttachmentFileName();                   
            //Note the file extension name may not be same as asset format name in some cases.
            if(binaryContentAttachmentFileName !=null && !"".equals(binaryContentAttachmentFileName)) {
                fileName = binaryContentAttachmentFileName;
            } else {
                fileName = asset.getName() + "." + asset.getFormat();
            }
            return Response.ok(asset.getBinaryContentAttachment()).header("Content-Disposition", "attachment; filename=" + fileName).build();
        } catch (RuntimeException e) {
            throw new WebApplicationException(e);
        }
    }
   
    //HTTP header names are case-insensitive
    private String getHttpHeader(HttpHeaders headers, String headerName) {

        MultivaluedMap<String, String> heads = headers.getRequestHeaders();
        Iterator<String> it = heads.keySet().iterator();
        while (it.hasNext()) {
            String key = it.next();
            if (headerName.equalsIgnoreCase(key)) {
                List<String> h = heads.get(key);

                if (h != null && h.size() > 0) {
                    return h.get(0);
                }
            }
        }

        return null;
    }

    @POST
    @Path("{packageName}/snapshot/{snapshotName}")
    public void createPackageSnapshot(
            @PathParam("packageName") final String packageName,
            @PathParam("snapshotName") final String snapshotName) throws SerializationException {
        compileModuleIfNeeded(packageName);
        repositoryModuleOperations.createModuleSnapshot(packageName,
                snapshotName, true, "REST API Snapshot",null,null,null,false,null,null,false,null);

    }

    private boolean assetExists(final String packageName, final String assetName) {
        /* Asset does not exist if package does not exist */
        final boolean packageExists = rulesRepository.containsModule(packageName);
        if (!packageExists){
            return false;
        }

        /* Load module and determine if it contains an asset */
        final ModuleItem packageItem = rulesRepository.loadModule(packageName);
        return packageItem.containsAsset(assetName);
    }

    @POST
    @Path("{packageName}/snapshot/{snapshotName}")
    @Consumes(MediaType.APPLICATION_XML)
    public void createPackageSnapshotWithOptions(
            @PathParam("packageName") final String packageName,
            @PathParam("snapshotName") final String snapshotName,SnapshotCreationData moduleData) throws SerializationException {
        compileModuleIfNeeded(packageName);
        repositoryModuleOperations.createModuleSnapshot(packageName,
                                                        snapshotName,
                                                        true,
                                                        "REST API Snapshot",
                                                        moduleData.getBuildMode(),
                                                        moduleData.getStatusOperator(),
                                                        moduleData.getStatusDescriptionValue(),
                                                        moduleData.getEnableStatusSelector(),
                                                        moduleData.getCategoryOperator(),
                                                        moduleData.getCategoryValue(),
                                                        moduleData.getEnableCategorySelector(),
                                                        moduleData.getCustomSelectorConfigName());
       
    }
   
    @POST
    @Path("{packageName}/assets")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Asset createAssetFromBinaryAndJAXB(@PathParam("packageName") String packageName, @MultipartForm AssetMultipartForm assetMultipartForm) {
        /* Verify passed in asset object */
        if (assetMultipartForm == null || assetMultipartForm.getAsset() == null || assetMultipartForm.getAsset().getMetadata() == null ){
            throw new WebApplicationException(Response.status(500).entity("Request must contain asset and metadata").build());
        }
        final String assetName = assetMultipartForm.getAsset().getTitle();

        /* Check for existence of asset name */
        if (assetName == null) {
            throw new WebApplicationException(Response.status(500).entity("Asset name must be specified (Asset.metadata.title)").build());
        }

        AssetItem ai = rulesRepository.loadModule(packageName).addAsset(assetName, assetMultipartForm.getAsset().getDescription());
        ai.checkout();
        ai.updateBinaryContentAttachmentFileName(assetMultipartForm.getAsset().getBinaryContentAttachmentFileName());
        ai.updateFormat(assetMultipartForm.getAsset().getMetadata().getFormat());
        ai.updateBinaryContentAttachment(assetMultipartForm.getBinary());
        ai.getModule().updateBinaryUpToDate(false);
        ai.updateValid(assetValidator.validate(ai));
        ai.checkin(assetMultipartForm.getAsset().getMetadata().getCheckInComment());
        rulesRepository.save();
        return assetMultipartForm.getAsset();
    }

    @PUT
    @Path("{packageName}/assets/{assetName}")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Asset updateAssetFromBinaryAndJAXB(@PathParam("packageName") final String packageName,@MultipartForm AssetMultipartForm assetMultipartForm, @PathParam("assetName") final String assetName) {
        /* Verify passed in asset object */
        if (assetMultipartForm == null || assetMultipartForm.getAsset() == null || assetMultipartForm.getAsset().getMetadata() == null ){
            throw new WebApplicationException(Response.status(500).entity("Request must contain asset and metadata").build());
        }

        /* Asset must exist to update */
        if (!assetExists(packageName, assetName)){
            throw new WebApplicationException(Response.status(500).entity("Asset [" + assetName + "] does not exist in package [" + packageName + "]").build());
        }

        AssetItem ai = rulesRepository.loadModule(packageName).loadAsset(assetName);
        ai.checkout();
        ai.updateDescription(assetMultipartForm.getAsset().getDescription());
        ai.updateBinaryContentAttachmentFileName(assetMultipartForm.getAsset().getBinaryContentAttachmentFileName());
        ai.updateFormat(assetMultipartForm.getAsset().getMetadata().getFormat());
        ai.updateBinaryContentAttachment(assetMultipartForm.getBinary());
        ai.getModule().updateBinaryUpToDate(false);
        ai.updateValid(assetValidator.validate(ai));
        ai.checkin(assetMultipartForm.getAsset().getMetadata().getCheckInComment());
        rulesRepository.save();
        return assetMultipartForm.getAsset();
    }
   
    private DateFormat createDateFormat(){
        return new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.US);
    }
   
    private Calendar convertToGmt(Calendar cal) {

        Date date = cal.getTime();
        TimeZone tz = cal.getTimeZone();

        //Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
        long msFromEpochGmt = date.getTime();

        //gives you the current offset in ms from GMT at the current date
        int offsetFromUTC = tz.getOffset(msFromEpochGmt);

        //create a new calendar in GMT timezone, set to this date and add the offset
        Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
        gmtCal.setTime(date);
        gmtCal.add(Calendar.MILLISECOND, offsetFromUTC);

        return gmtCal;
    }
}

TOP

Related Classes of org.drools.guvnor.server.jaxrs.PackageResource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.