/* * Copyright (c) 2010 Red Hat, 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.ovirt.engine.api.restapi.resource; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import org.ovirt.engine.api.common.util.JAXBHelper; import org.ovirt.engine.api.common.util.LinkHelper; import org.ovirt.engine.api.common.util.LinkHelper.LinkFlags; import org.ovirt.engine.api.common.util.QueryHelper; import org.ovirt.engine.api.model.API; import org.ovirt.engine.api.model.ApiSummary; import org.ovirt.engine.api.model.BaseResource; import org.ovirt.engine.api.model.DetailedLink; import org.ovirt.engine.api.model.Hosts; import org.ovirt.engine.api.model.Link; import org.ovirt.engine.api.model.LinkHeader; import org.ovirt.engine.api.model.ObjectFactory; //import org.ovirt.engine.api.model.Parameter; //import org.ovirt.engine.api.model.ParametersSet; import org.ovirt.engine.api.model.ProductInfo; import org.ovirt.engine.api.model.RSDL; //import org.ovirt.engine.api.model.SpecialObjects; //import org.ovirt.engine.api.model.StorageDomains; import org.ovirt.engine.api.model.Users; //import org.ovirt.engine.api.model.VMs; import org.ovirt.engine.api.resource.ApiResource; import org.ovirt.engine.api.common.util.FileUtils; import org.ovirt.engine.api.restapi.util.VersionHelper; import org.ovirt.engine.core.common.queries.ConfigurationValues; import org.ovirt.engine.core.common.queries.GetSystemStatisticsQueryParameters; import org.ovirt.engine.core.common.queries.VdcQueryReturnValue; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.api.restapi.rsdl.RsdlBuilder; import org.ovirt.engine.api.restapi.rsdl.SchemaBuilder; public class BackendApiResource extends BackendResource implements ApiResource { private static final String SYSTEM_STATS_ERROR = "Unknown error querying system statistics"; private static final String RESOURCES_PACKAGE = "org.ovirt.engine.api.resource"; private static final String API_SCHEMA = "api.xsd"; private static final String RSDL_CONSTRAINT_PARAMETER = "rsdl"; private static final String RSDL_REL = "rsdl"; private static final String SCHEMA_REL = "schema"; private static final String SCHEMA_CONSTRAINT_PARAMETER = "schema"; private static final String RSDL_DESCRIPTION = "The Gluster RESTful API description language."; private static final String SCHEMA_DESCRIPTION = "oVirt API entities schema."; private static final String SCHEMA_NAME = "ovirt-engine-api-schema.xsd"; private static RSDL rsdl = null; private static final String QUERY_PARAMETER = "?"; protected final ObjectFactory OBJECT_FACTORY = new ObjectFactory(); private Collection<DetailedLink> getLinks() { Collection<DetailedLink> links = new LinkedList<DetailedLink>(); // links.add(createLink("capabilities")); links.add(createLink("clusters", LinkFlags.SEARCHABLE)); links.add(createLink("datacenters", LinkFlags.SEARCHABLE)); // links.add(createLink("events", LinkFlags.SEARCHABLE, getEventParams())); links.add(createLink("hosts", LinkFlags.SEARCHABLE)); // links.add(createLink("networks")); // links.add(createLink("roles")); // links.add(createLink("storagedomains", LinkFlags.SEARCHABLE)); // links.add(createLink("tags")); // links.add(createLink("templates", LinkFlags.SEARCHABLE)); // links.add(createLink("users", LinkFlags.SEARCHABLE)); // links.add(createLink("groups", LinkFlags.SEARCHABLE)); // links.add(createLink("domains")); // links.add(createLink("vmpools", LinkFlags.SEARCHABLE)); // links.add(createLink("vms", LinkFlags.SEARCHABLE)); return links; } private API getApi() { API api = new API(); for (DetailedLink detailedLink : getLinks()) { //add thin link api.getLinks().add(LinkHelper.createLink(detailedLink.getHref(), detailedLink.getRel())); //when required - add extra link for search if (detailedLink.isSetLinkCapabilities() && detailedLink.getLinkCapabilities().isSetSearchable() && detailedLink.getLinkCapabilities().isSearchable()) { api.getLinks().add(LinkHelper.createLink(detailedLink.getHref(), detailedLink.getRel(), detailedLink.getRequest().getUrl().getParametersSets())); } } return api; } // private ParametersSet getEventParams() { // ParametersSet ps = new ParametersSet(); // Parameter param = new Parameter(); // param.setName("from"); // param.setValue("event_id"); // ps.getParameters().add(param); // return ps; // } public List<String> getRels() { List<String> rels = new ArrayList<String>(); for (Link link : getLinks()) { rels.add(link.getRel()); } return rels; } // private BaseResource getSpecialObjects(API api) { // api.setSpecialObjects(new SpecialObjects()); // return api.getSpecialObjects(); // } // // private String getTagRootUri() { // return LinkHelper.combine(getUriInfo().getBaseUri().getPath(), "tags/00000000-0000-0000-0000-000000000000"); // } // // private String getTemplateBlankUri() { // return LinkHelper.combine(getUriInfo().getBaseUri().getPath(), "templates/00000000-0000-0000-0000-000000000000"); // } // // private void addStaticLinks(List<Link> linker, String[] rels, String[] refs) { // if(rels.length == refs.length){ // for(int i = 0; i < rels.length; i++){ // Link link = new Link(); // link.setRel(rels[i]); // link.setHref(refs[i]); // linker.add(link); // } // } // } private DetailedLink createLink(String rel, LinkFlags flags) { return LinkHelper.createLink(getUriInfo().getBaseUri().getPath(), rel, flags); } // private DetailedLink createLink(String rel, LinkFlags flags, ParametersSet params) { // return LinkHelper.createLink(getUriInfo().getBaseUri().getPath(), rel, flags, params); // } // // private DetailedLink createLink(String rel) { // return LinkHelper.createLink(getUriInfo().getBaseUri().getPath(), rel, LinkFlags.NONE); // } private String addPath(UriBuilder uriBuilder, Link link) { String query = ""; String path = relative(link); // otherwise UriBuilder.build() will substitute {query} if (path.contains("?")) { query = path.substring(path.indexOf("?")); path = path.substring(0, path.indexOf("?")); } link = JAXBHelper.clone(OBJECT_FACTORY.createLink(link)); link.setHref(uriBuilder.clone().path(path).build() + query); return LinkHeader.format(link); } private void addHeader(BaseResource response, Response.ResponseBuilder responseBuilder, UriBuilder uriBuilder) { // concantenate links in a single header with a comma-separated value, // which is the canonical form according to: // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 // StringBuffer header = new StringBuffer(); for (Link l : response.getLinks()) { header.append(addPath(uriBuilder, l)).append(","); } header.setLength(header.length() - 1); responseBuilder.header("Link", header); } private Response.ResponseBuilder getResponseBuilder(BaseResource response) { UriBuilder uriBuilder = getUriInfo().getBaseUriBuilder(); Response.ResponseBuilder responseBuilder = Response.ok(); if(response instanceof API) { addHeader(response, responseBuilder, uriBuilder); } return responseBuilder; } @Override public Response head() { API api = getApi(); return getResponseBuilder(api).build(); } @Override public Response get() { if (QueryHelper.hasConstraint(getUriInfo(), RSDL_CONSTRAINT_PARAMETER)) { RSDL rsdl = addSystemVersion(getRSDL()); return Response.ok().entity(rsdl).build(); } else if (QueryHelper.hasConstraint(getUriInfo(), SCHEMA_CONSTRAINT_PARAMETER)) { return getSchema(); } else { BaseResource response = addSummary(addSystemVersion(getApi())); return getResponseBuilder(response).entity(response).build(); } } private Response getSchema() { ByteArrayOutputStream baos = null; InputStream is = null; int thisLine; try { baos = new ByteArrayOutputStream(); is = FileUtils.get(RESOURCES_PACKAGE, API_SCHEMA); while ((thisLine = is.read()) != -1) { baos.write(thisLine); } baos.flush(); return Response.ok(baos.toByteArray(), MediaType.APPLICATION_OCTET_STREAM) .header("content-disposition","attachment; filename = " + SCHEMA_NAME) .build(); } catch (IOException e) { LOG.error("Loading api.xsd file failed.", e); return Response.serverError().build(); } finally { try { if (baos != null) baos.close(); if (is != null) is.close(); } catch (IOException e) {;} } } private RSDL addSystemVersion(RSDL rsdl) { rsdl.setVersion(VersionHelper.parseVersion(getConfigurationValue(String.class, ConfigurationValues.VdcVersion, null))); return rsdl; } private synchronized RSDL getRSDL() { if (rsdl == null) { rsdl = new RsdlBuilder(this).description(RSDL_DESCRIPTION). rel(RSDL_REL). href(getUriInfo().getBaseUri().getPath() + QUERY_PARAMETER + RSDL_CONSTRAINT_PARAMETER). schema(new SchemaBuilder().rel(SCHEMA_REL) .href(getUriInfo().getBaseUri().getPath() + QUERY_PARAMETER + SCHEMA_CONSTRAINT_PARAMETER) .name(SCHEMA_NAME) .description(SCHEMA_DESCRIPTION) .build()). build(); } return rsdl; } private API addSystemVersion(API api) { api.setProductInfo(new ProductInfo()); api.getProductInfo().setName("oVirt Enterprise Virtualization Engine"); api.getProductInfo().setVendor("Red Hat"); api.getProductInfo().setVersion(VersionHelper.parseVersion(getConfigurationValue(String.class, ConfigurationValues.VdcVersion, null))); return api; } private HashMap<String, Integer> getSystemStatistics() { try { VdcQueryReturnValue result = backend.RunQuery(VdcQueryType.GetSystemStatistics, sessionize(new GetSystemStatisticsQueryParameters(-1))); if (!result.getSucceeded() || result.getReturnValue() == null) { String failure; if (result.getExceptionString() != null) { failure = localize(result.getExceptionString()); } else { failure = SYSTEM_STATS_ERROR; } throw new BackendFailureException(failure); } return asStatisticsMap(result.getReturnValue()); } catch (Exception e) { return handleError(e, false); } } @SuppressWarnings("unchecked") private HashMap<String, Integer> asStatisticsMap(Object result) { return (HashMap<String, Integer>)result; } private API addSummary(API api) { HashMap<String, Integer> stats = getSystemStatistics(); ApiSummary summary = new ApiSummary(); // summary.setVMs(new VMs()); // summary.getVMs().setTotal(get(stats, "total_vms")); // summary.getVMs().setActive(get(stats, "active_vms")); summary.setHosts(new Hosts()); summary.getHosts().setTotal(get(stats, "total_vds")); summary.getHosts().setActive(get(stats, "active_vds")); summary.setUsers(new Users()); summary.getUsers().setTotal(get(stats, "total_users")); summary.getUsers().setActive(get(stats, "active_users")); // summary.setStorageDomains(new StorageDomains()); // summary.getStorageDomains().setTotal(get(stats, "total_storage_domains")); // summary.getStorageDomains().setActive(get(stats, "active_storage_domains")); api.setSummary(summary); return api; } private long get(HashMap<String, Integer> stats, String key) { return stats.get(key).longValue(); } private String relative(Link link) { return link.getHref().substring(link.getHref().indexOf(link.getRel().split("/")[0]), link.getHref().length()); } }