package org.hyperic.hq.api.services.impl; import org.apache.cxf.jaxrs.ext.search.ConditionType; import org.apache.cxf.jaxrs.ext.search.PrimitiveStatement; import org.apache.cxf.jaxrs.ext.search.SearchCondition; import org.apache.cxf.jaxrs.ext.search.SearchConditionVisitor; import org.apache.cxf.jaxrs.ext.search.SearchContext; import org.hibernate.ObjectNotFoundException; import org.hyperic.hq.api.model.common.RegistrationID; import org.hyperic.hq.api.model.common.ExternalRegistrationStatus; import org.hyperic.hq.api.model.measurements.MeasurementAlias; import org.hyperic.hq.api.model.measurements.MetricFilterRequest; import org.hyperic.hq.api.model.measurements.MetricResponse; import org.hyperic.hq.api.model.measurements.ResourceMeasurement; import org.hyperic.hq.api.model.measurements.ResourceMeasurementBatchResponse; import org.hyperic.hq.api.model.measurements.ResourceMeasurementRequest; import org.hyperic.hq.api.model.measurements.ResourceMeasurementRequests; import org.hyperic.hq.api.services.MetricService; import org.hyperic.hq.api.transfer.MeasurementTransfer; import org.hyperic.hq.api.transfer.mapping.ExceptionToErrorCodeMapper; import org.hyperic.hq.api.transfer.mapping.UnknownEndpointException; import org.hyperic.hq.auth.shared.SessionNotFoundException; import org.hyperic.hq.auth.shared.SessionTimeoutException; import org.hyperic.hq.authz.shared.PermissionException; import org.hyperic.hq.common.NotFoundException; import org.hyperic.hq.common.TimeframeBoundriesException; import org.hyperic.hq.measurement.server.session.Measurement; import org.hyperic.hq.measurement.server.session.MeasurementTemplate; import org.hyperic.hq.measurement.server.session.TimeframeSizeException; import org.hyperic.hq.notifications.EndpointQueue; import org.hyperic.hq.notifications.NotificationEndpoint; import org.springframework.beans.factory.annotation.Autowired; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import java.sql.SQLException; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Stack; public class MetricServiceImpl extends RestApiService implements MetricService { @Autowired protected MeasurementTransfer measurementTransfer; @Autowired protected ExceptionToErrorCodeMapper errorHandler; @Autowired private EndpointQueue endpointQueue; @Context private SearchContext searchContext; protected String extractAliases(SearchCondition<MeasurementAlias> sc) { String ma = sc.getCondition().getMeasurementAlias(); ConditionType ct = sc.getConditionType(); if (!ct.equals(ConditionType.EQUALS)) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.ILLEGAL_FILTER_COMPARATOR, ct.toString(), ResourceMeasurement.MEASUREMENT_ALIAS, ma, ConditionType.EQUALS.toString()); } return ma; } public MetricResponse getMetrics(final Date begin, final Date end) throws Throwable { try { try { SearchCondition<ResourceMeasurement> scRoot = this.searchContext.getCondition(ResourceMeasurement.class); if (scRoot==null) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.ILLEGAL_FILTER, " (most likley that the supplied field name is not " + ResourceMeasurement.MEASUREMENT_ALIAS + ", the comparator type is unrecognized or that the value it is compared against is empty)\n Only the following filter form is acceptable: " + ResourceMeasurement.MEASUREMENT_ALIAS + "=<string>," + ResourceMeasurement.MEASUREMENT_ALIAS + "=<string>,..."); } ResourceMeasurementFIQLVisitor visitor = new ResourceMeasurementFIQLVisitor(); try { scRoot.accept(visitor); } catch (IllegalFIQLStructure e) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.ILLEGAL_FILTER, e.getMessage()); } ResourceMeasurementRequests rs = visitor.getResourceMeasurementRequests(); if (rs==null) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.ILLEGAL_FILTER, ""); } ResourceMeasurementRequest hqMsmtReq = rs.getMeasurementRequests().get(0); ApiMessageContext apiMessageContext = newApiMessageContext(); return measurementTransfer.getMetrics(apiMessageContext, hqMsmtReq.getMeasurementTemplateNames(), hqMsmtReq.getRscId(), begin, end); } catch (Throwable t) { errorHandler.log(t); throw t; } } catch (TimeframeSizeException e) { throw errorHandler.newWebApplicationException(e, Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.WRONG_DATE_VALUES, e.getMessage()); } catch (TimeframeBoundriesException e) { throw errorHandler.newWebApplicationException(e, Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.WRONG_DATE_VALUES, e.getMessage()); } catch (UnsupportedOperationException e) { throw errorHandler.newWebApplicationException(e, Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.BAD_MEASUREMENT_REQ, e.getMessage()); } catch (ObjectNotFoundException e) { String missingObj = e.getEntityName(); if (MeasurementTemplate.class.getName().equals(missingObj)) { throw errorHandler.newWebApplicationException(e, Response.Status.NOT_FOUND, ExceptionToErrorCodeMapper.ErrorCode.TEMPLATE_NOT_FOUND); } if (Measurement.class.getName().equals(missingObj)) { throw errorHandler.newWebApplicationException(e, Response.Status.NOT_FOUND, ExceptionToErrorCodeMapper.ErrorCode.MEASUREMENT_NOT_FOUND); } throw errorHandler.newWebApplicationException(e, Response.Status.NOT_FOUND, ExceptionToErrorCodeMapper.ErrorCode.RESOURCE_NOT_FOUND_BY_ID); } } public ResourceMeasurementBatchResponse getAggregatedMetricData(Date begin, Date end) throws ParseException, PermissionException, SessionNotFoundException, SessionTimeoutException, ObjectNotFoundException, UnsupportedOperationException, SQLException { try { SearchCondition<ResourceMeasurement> scRoot = this.searchContext.getCondition(ResourceMeasurement.class); if (scRoot==null) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.ILLEGAL_AGG_FILTER, " (most likley that one of the supplied field names is not recognized, a needed field name is missing, the comparator type is unrecognized or that the value it is compared against is empty)"); } ResourceMeasurementFIQLVisitor visitor = new ResourceMeasurementFIQLVisitor(); try { scRoot.accept(visitor); } catch (IllegalFIQLStructure e) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.ILLEGAL_AGG_FILTER, e.getMessage()); } ResourceMeasurementRequests hqMsmtReqs = visitor.getResourceMeasurementRequests(); if (hqMsmtReqs==null) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.ILLEGAL_FILTER, ""); } ApiMessageContext apiMessageContext = newApiMessageContext(); return measurementTransfer.getAggregatedMetricData(apiMessageContext, hqMsmtReqs, begin, end); } catch (TimeframeBoundriesException e) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.WRONG_DATE_VALUES, e.getMessage()); } } public RegistrationID register(final MetricFilterRequest request) throws SessionNotFoundException, SessionTimeoutException { ApiMessageContext apiMessageContext = newApiMessageContext(); try { return measurementTransfer.register(apiMessageContext, request, apiMessageContext); } catch (PermissionException e) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.UNAUTHORIZED, ExceptionToErrorCodeMapper.ErrorCode.NON_ADMIN_ERR, ""); } } public ExternalRegistrationStatus getRegistrationStatus(final String registrationID) throws SessionNotFoundException, SessionTimeoutException, PermissionException, NotFoundException { ApiMessageContext apiMessageContext = newApiMessageContext(); try { return measurementTransfer.getRegistrationStatus(apiMessageContext, registrationID); }catch(UnknownEndpointException e) { e.printStackTrace(); throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.INTERNAL_SERVER_ERROR, ExceptionToErrorCodeMapper.ErrorCode.UNKNOWN_ENDPOINT, e.getRegistrationID()); } catch (PermissionException e) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.UNAUTHORIZED, ExceptionToErrorCodeMapper.ErrorCode.NON_ADMIN_ERR, ""); } } public void unregister(final String registrationId) throws SessionNotFoundException, SessionTimeoutException { NotificationEndpoint endpoint = endpointQueue.unregister(registrationId); if (endpoint == null) { throw errorHandler.newWebApplicationException(Response.Status.BAD_REQUEST, ExceptionToErrorCodeMapper.ErrorCode.RESOURCE_NOT_FOUND_BY_ID); } try { ApiMessageContext apiMessageContext = newApiMessageContext(); measurementTransfer.unregister(apiMessageContext,endpoint); } catch (PermissionException e) { throw errorHandler.newWebApplicationException(new Throwable(), Response.Status.UNAUTHORIZED, ExceptionToErrorCodeMapper.ErrorCode.NON_ADMIN_ERR, ""); } } protected static class ResourceMeasurementFIQLVisitor implements SearchConditionVisitor<ResourceMeasurement> { protected Stack<Object> s = new Stack<Object>(); @SuppressWarnings("unchecked") public void visit(SearchCondition<ResourceMeasurement> sc) { if (sc==null) { throw new IllegalFIQLStructure("no filter supplied"); } ConditionType ct = sc.getConditionType(); if (ct.equals(ConditionType.OR)) { this.s.add(ConditionType.OR); List<SearchCondition<ResourceMeasurement>> scChildren = sc.getSearchConditions(); for(SearchCondition<ResourceMeasurement> scChild:scChildren) { scChild.accept(this); } Object o = this.s.pop(); List l = new ArrayList<Object>(); boolean childrenRepresentsAlias = false; while (!ConditionType.OR.equals(o)) { if (o instanceof String[]) { if (!l.isEmpty() && !childrenRepresentsAlias) { throw new IllegalFIQLStructure("the following filter structure form is illegal: "+ ResourceMeasurement.RESOURCE_ID+"==<string>," + ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>"); } String[] kv = (String[]) o; if (ResourceMeasurement.MEASUREMENT_ALIAS.equals(kv[0])) { l.add((String)kv[1]); } else { throw new IllegalFIQLStructure("in a filter, only '" + ResourceMeasurement.MEASUREMENT_ALIAS + "' fields and elements of the form '("+ ResourceMeasurement.RESOURCE_ID+"==<string>;(" + ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>," + ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>,..))' may be seperated with ','"); } childrenRepresentsAlias=true; } else if (o instanceof ResourceMeasurementRequest) { if (!l.isEmpty() && childrenRepresentsAlias) { throw new IllegalFIQLStructure("the following filter structure form is illegal: "+ ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>," + ResourceMeasurement.RESOURCE_ID + "==<string>"); } l.add(o); childrenRepresentsAlias=false; } else { throw new IllegalFIQLStructure("the following element was found next to a ',': " + o); } o = this.s.pop(); } if (childrenRepresentsAlias) { this.s.add(l); } else { ResourceMeasurementRequests rs = new ResourceMeasurementRequests(); rs.setMeasurementRequests(l); this.s.add(rs); } } else if (ct.equals(ConditionType.AND)) { this.s.add(ConditionType.AND); List<SearchCondition<ResourceMeasurement>> scChildren = sc.getSearchConditions(); for(SearchCondition<ResourceMeasurement> scChild:scChildren) { scChild.accept(this); } Object o = this.s.pop(); ResourceMeasurementRequest r = new ResourceMeasurementRequest(); boolean listMet = false; while (!ConditionType.AND.equals(o)) { if (o instanceof List) { if (listMet) { throw new IllegalFIQLStructure("the following filter structure form is illegal: "+ ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>;" + ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>"); } r.setMeasurementTemplateNames((List<String>) o); listMet = true; } else if (o instanceof String[]){ String[] kv = (String[]) o; if (ResourceMeasurement.RESOURCE_ID.equals(kv[0])) { r.setRscId((String)kv[1]); } else if (ResourceMeasurement.MEASUREMENT_ALIAS.equals(kv[0])) { if (listMet) { throw new IllegalFIQLStructure("the following filter structure form is illegal: "+ ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>;" + ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>"); } List<String> aliases = new ArrayList<String>(); aliases.add((String) kv[1]); r.setMeasurementTemplateNames(aliases); } else { throw new IllegalFIQLStructure("illegal property name. Only "+ ResourceMeasurement.RESOURCE_ID+" and " + ResourceMeasurement.MEASUREMENT_ALIAS + " are allowed"); } } else { throw new IllegalFIQLStructure("in a filter, ';' can only come between '"+ ResourceMeasurement.RESOURCE_ID+"==<string>' and "+ "'" + ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>', or between '"+ ResourceMeasurement.RESOURCE_ID+"==<string>' and "+ "'(" + ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>," + ResourceMeasurement.MEASUREMENT_ALIAS + "==<string>,..)'"); } o = this.s.pop(); } this.s.add(r); } else if (ct.equals(ConditionType.EQUALS)) { PrimitiveStatement ps = sc.getStatement(); String[] kv = new String[2]; kv[0] = ps.getProperty(); kv[1] = (String) ps.getValue(); this.s.add(kv); } else { throw new IllegalFIQLStructure("unexpected filter element " + ct); } } public ResourceMeasurementRequests getResourceMeasurementRequests() { Object o = this.s.pop(); if (o instanceof ResourceMeasurementRequests) { return (ResourceMeasurementRequests) o; } if (o instanceof ResourceMeasurementRequest) { ResourceMeasurementRequests rs = new ResourceMeasurementRequests(); rs.addMeasurementRequests((ResourceMeasurementRequest) o); return rs; } return null; } public String getResult() { return null; } } protected static class IllegalFIQLStructure extends RuntimeException { private static final long serialVersionUID = -2683108375142690198L; public IllegalFIQLStructure(String msg) { super(msg); } } }