/** * Copyright 2014 Comcast Cable Communications Management, LLC * * This file is part of CATS. * * CATS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CATS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CATS. If not, see <http://www.gnu.org/licenses/>. */ package com.comcast.cats.domain.service; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.inject.Named; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; import com.comcast.cats.domain.AllocationCategory; import com.comcast.cats.domain.configuration.CatsProperties; import com.comcast.cats.domain.exception.DomainServiceException; import com.comcast.cats.domain.util.AssertUtil; import com.comcast.cats.domain.util.CommonUtil; import com.comcast.cats.domain.util.HtmlUtil; import com.comcast.cats.domain.util.SSLUtil; /** * <p> * Common features of Domain services. {@link RestTemplate} , * {@link DomainProperties} and logger instances are available to subclass. * </p> * <p> * Since the configuration management system is running under HTTPS, * Any Java client which uses domain APIs need to have a valid SSL certificate * installed in the client machine. * </p> * <p> * As installing SSL client certificate in every client machine is not feasible, * we need to disable the SSL certificate validation. The static block here will * do exactly the same. * </p> * * @author subinsugunan * * @param <Type> */ @Named public abstract class AbstractService< Type > { static { SSLUtil.disableCertificateValidation(); } @Inject protected RestTemplateProducer restTemplateProducer; @Inject protected CatsProperties properties; /** * All subclass should use this. */ protected final Logger logger = LoggerFactory.getLogger( getClass() ); /** * Common constants used by domain service classes */ protected static final Integer DEFAULT_COUNT = 0; protected static final Integer DEFAULT_OFFSET = 0; // Special characters protected static final String BACK_SLASH = "/"; protected static final String PARAM_SEPARATOR = "&"; protected static final String QUESTION_MARK = "?"; protected static final String EQUALS = "="; // URL Parameters protected static final String ALL = "all"; protected static final String LIST = "list"; protected static final String LIST_AVAILABLE = "list-available"; protected static final String LIST_ACTIVE = "list-active"; protected static final String COUNT = "count"; protected static final String COUNT_AVAILABLE = "count-available"; protected static final String COUNT_ACTIVE = "count-active"; protected static final String ACTIVE = "active"; protected static final String AUTH_TOKEN = "token"; protected static final String OFFSET = "offset"; protected static final String PROPERTY = "property"; protected static final String PROPERTY_NAME = "name"; protected static final String PROPERTY_VALUE = "value"; protected static final String CRITERIA = "criteria"; protected static final String SHALLOW = "shallow"; protected static final String ID = "id"; protected static final String MAC_ID = "macid"; protected static final String DURATION = "duration"; protected static final String SHOW = "show"; protected static final String UPDATE = "update"; protected static final String RELEASE = "release"; protected static final String ALLOCATE = "allocate"; protected static final String ALLOCATED = "allocated"; protected static final String AVAILABLE = "available"; protected static final String VERIFY = "verify"; protected static final String ALLOCATION_CATEGORY = "category"; protected static final String REACQUIRE_FLAG = "reacquire"; // Domains protected static final String SETTOP = "settop"; protected static final String SETTOPS = "settops"; protected static final String SETTOP_GROUP = "settopGroup"; protected static final String SETTOP_GROUPS = "settopGroups"; protected static final String RESERVATION = "reservation"; protected static final String RESERVATIONS = "reservations"; protected static final String RACK = "rack"; protected static final String RACKS = "racks"; protected static final String SLOTS = "slots"; protected static final String ALLOCATION = "allocation"; protected static final String ALLOCATIONS = "allocations"; protected static final String COMPONENT = "component"; protected static final String USER = "user"; protected static final String USERS = "users"; protected static final String USER_GROUPS = "userGroups"; protected static final String SERVER = "server"; protected static final String SERVICE = "service"; protected static final String ENVIRONMENT = "environment"; protected static final String MDS = "mds"; private static final String UTF_8 = "UTF-8"; /** * To get the response as domain type. * * @param requestUrl * @param domainClass * @return Type * @throws DomainServiceException * {@link DomainServiceException} */ protected Type getResponseAsDomain( String requestUrl, Class< Type > domainClass ) throws DomainServiceException { validateAndLogRequest( HttpMethod.GET, requestUrl ); Type type = null; try { type = ( Type ) restTemplateProducer.getRestTemplate().getForObject( requestUrl, domainClass ); } catch ( Exception e ) { handleException( e, HttpMethod.GET, requestUrl ); } return type; } /** * To get the response as String. * * @param requestUrl * @return String * @throws DomainServiceException * {@link DomainServiceException} */ protected String getResponseAsString( String requestUrl ) throws DomainServiceException { validateAndLogRequest( HttpMethod.GET, requestUrl ); String response = null; try { response = ( String ) restTemplateProducer.getRestTemplate().getForObject( requestUrl, String.class ); } catch ( Exception e ) { handleException( e, HttpMethod.GET, requestUrl ); } return response; } /** * To get the response as number. * * @param requestUrl * @return Integer * @throws DomainServiceException * {@link DomainServiceException} */ protected Integer getResponseAsNumber( String requestUrl ) throws DomainServiceException { Integer count = 0; count = Integer.parseInt( getResponseAsString( requestUrl ) ); return count; } /** * To get the response as Boolean. * * @param requestUrl * @return Boolean * @throws DomainServiceException * {@link DomainServiceException} */ protected Boolean getResponseAsBoolean( String requestUrl ) throws DomainServiceException { Boolean response = false; response = Boolean.parseBoolean( getResponseAsString( requestUrl ) ); return response; } /** * To get the response as domain type. * * @param requestUrl * @param clazz * @return List of Type * @throws DomainServiceException * {@link DomainServiceException} */ @SuppressWarnings( "unchecked" ) protected List< Type > getResponseAsDomainList( String requestUrl, Class< Type > clazz ) throws DomainServiceException { validateAndLogRequest( HttpMethod.GET, requestUrl ); List< Type > responselist = Collections.emptyList(); try { responselist = ( List< Type > ) restTemplateProducer.getRestTemplate().getForObject( requestUrl, clazz ); } catch ( Exception e ) { handleException( e, HttpMethod.GET, requestUrl ); } return responselist; } /** * Post for domain object * * @param requestUrl * @param clazz * @return Type * @throws DomainServiceException * {@link DomainServiceException} */ protected Type postForDomainObject( String requestUrl, Class< Type > clazz ) throws DomainServiceException { validateAndLogRequest( HttpMethod.POST, requestUrl ); Type type = null; try { type = ( Type ) restTemplateProducer.getRestTemplate().postForObject( requestUrl, null, clazz ); } catch ( Exception e ) { handleException( e, HttpMethod.POST, requestUrl ); } return type; } /** * Post for String * * @param requestUrl * @return String * @throws DomainServiceException * {@link DomainServiceException} */ protected String postForString( String requestUrl ) throws DomainServiceException { validateAndLogRequest( HttpMethod.POST, requestUrl ); String type = null; try { type = ( String ) restTemplateProducer.getRestTemplate().postForObject( requestUrl, null, String.class ); } catch ( Exception e ) { handleException( e, HttpMethod.POST, requestUrl ); } return type; } /** * to put request * * @param requestUrl * @throws DomainServiceException * {@link DomainServiceException} */ protected void put( String requestUrl ) throws DomainServiceException { validateAndLogRequest( HttpMethod.PUT, requestUrl ); try { restTemplateProducer.getRestTemplate().put( requestUrl, null ); } catch ( Exception e ) { handleException( e, HttpMethod.PUT, requestUrl ); } } /** * to handle exception * * @param e * @param httpMethod * @param requestUrl * @throws DomainServiceException * {@link DomainServiceException} */ protected void handleException( Exception e, HttpMethod httpMethod, String requestUrl ) throws DomainServiceException { if ( e instanceof HttpClientErrorException ) { handleHttpClientErrorException( ( ( HttpClientErrorException ) e ), httpMethod, requestUrl ); } throw new RuntimeException( "[REST-" + httpMethod + "] Error communicating with server. Make sure all the inputs are valid. " + e.getMessage() ); } private void handleHttpClientErrorException( HttpClientErrorException httpClientErrorException, HttpMethod httpMethod, String requestUrl ) throws DomainServiceException { HttpStatus statusCode = httpClientErrorException.getStatusCode(); String responseBody = httpClientErrorException.getResponseBodyAsString(); String responseMessage = null; if ( ( null != responseBody ) && ( !responseBody.isEmpty() ) ) { responseMessage = HtmlUtil.getErrorMessage( httpClientErrorException.getResponseBodyAsString() ); } else { responseMessage = httpClientErrorException.getMessage(); } logger.error( "[REST-" + httpMethod + "][HTTP-" + statusCode + "][URL-" + requestUrl + "] " + responseMessage ); throw new DomainServiceException( responseMessage, statusCode.value() ); } /** * to validate and log the request. * * @param method * @param requestUrl */ protected void validateAndLogRequest( HttpMethod method, String requestUrl ) { AssertUtil.isNullOrEmpty( requestUrl, "Cannot process request. requestUrl cannot be null or empty" ); logger.info( "[REST-" + method + "][URL-" + requestUrl + "]" ); } /** * to get the base url. * * @param domain * @return String */ protected String getBaseUrl( String domain ) { return properties.getConfigServerUrl() + domain + BACK_SLASH; } /** * to get the parameter map by token. * * @return Map */ protected Map< String, String > getParamMapByToken() { Map< String, String > params = new HashMap< String, String >(); addAuthTokenToParamMap( params ); return params; } /** * to get the parameter map by token. * * @param authToken * @return Map */ protected Map< String, String > getParamMapByToken( String authToken ) { Map< String, String > params = new HashMap< String, String >(); addAuthTokenToParamMap( params, authToken ); return params; } /** * to get the parameter map by id * * @param id * @param offset * @param count * @param shallow * @return Map */ protected Map< String, String > getParamMapById( String id, Integer offset, Integer count, Boolean isShallow ) { Map< String, String > params = new HashMap< String, String >(); addIdToParamMap( params, id ); addOffsetToParamMap( params, offset, count ); addShallowToPramMap( params, isShallow ); return params; } /** * * @param id * @param offset * @param count * @return */ protected Map< String, String > getParamMapById( String id, Integer offset, Integer count ) { Map< String, String > params = new HashMap< String, String >(); addIdToParamMap( params, id ); addOffsetToParamMap( params, offset, count ); return params; } /** * to get the parameter map by mac id. * * @param macId * @return Map */ protected Map< String, String > getParamMapByMacId( String macId ) { Map< String, String > params = new HashMap< String, String >(); addMacIdToParamMap( params, macId ); return params; } /** * to get the parameter map by id and token. * * @param id * @return Map */ protected Map< String, String > getParamMapByIdAndToken( String id ) { return getParamMapByIdAndToken( id, 0, 0 ); } /** * to get the parameter map by id and token. * * @param id * @param offset * @param count * @return Map */ protected Map< String, String > getParamMapByIdAndToken( String id, Integer offset, Integer count ) { Map< String, String > params = new HashMap< String, String >(); addIdToParamMap( params, id ); addOffsetToParamMap( params, offset, count ); addAuthTokenToParamMap( params ); return params; } /** * to get the parameter map by id and token. * * @param id * @param offset * @param count * @param isShallow * @return Map */ protected Map< String, String > getParamMapByIdAndToken( String id, Integer offset, Integer count, Boolean isShallow ) { Map< String, String > params = new HashMap< String, String >(); addIdToParamMap( params, id ); addOffsetToParamMap( params, offset, count ); addAuthTokenToParamMap( params ); addShallowToPramMap( params, isShallow ); return params; } /** * to get the parameter map by id and token. * * @param id * @param authToken * @return Map */ protected Map< String, String > getParamMapByIdAndToken( String id, String authToken ) { Map< String, String > params = new HashMap< String, String >(); addIdToParamMap( params, id ); addAuthTokenToParamMap( params, authToken ); return params; } /** * to get the parameter map by id and duration. * * @param id * @param duration * @return Map */ protected Map< String, String > getParamMapByIdDurationAndToken( String id, Integer duration ) { Map< String, String > params = new HashMap< String, String >(); addIdToParamMap( params, id ); addDurationToParamMap( params, duration ); addAuthTokenToParamMap( params ); return params; } /** * to get the parameter map by id, duration and token. * * @param id * @param duration * @param authToken * @return Map */ protected Map< String, String > getParamMapByIdDurationAndToken( String id, Integer duration, String authToken ) { Map< String, String > params = new HashMap< String, String >(); addIdToParamMap( params, id ); addDurationToParamMap( params, duration ); addAuthTokenToParamMap( params, authToken ); return params; } /** * to get the parameter map by id, duration, token and allocationCategory. * * @param id * @param duration * @param authToken * @param allocationCategory * {@link AllocationCategory} * @param reacquire * @return Map */ protected Map< String, String > getParamMapByIdDurationAndToken( String id, Integer duration, String authToken, AllocationCategory allocationCategory, Boolean reacquire ) { Map< String, String > params = new HashMap< String, String >(); addIdToParamMap( params, id ); addDurationToParamMap( params, duration ); addAuthTokenToParamMap( params, authToken ); addAllocationCategoryToParamMap( params, allocationCategory.toString() ); addReacquireFlagToParamMap( params, reacquire ); return params; } /** * to get the parameter map by name. * * @param name * @param offset * @param count * @return Map */ protected Map< String, String > getParamMapByName( String name, Integer offset, Integer count, Boolean isShallow ) { Map< String, String > params = new HashMap< String, String >(); addNameToParamMap( params, name ); addOffsetToParamMap( params, offset, count ); addShallowToPramMap( params, isShallow ); return params; } /** * to get the parameter map by name and token. * * @param name * @param offset * @param count * @return Map */ protected Map< String, String > getParamMapByNameAndToken( String name, Integer offset, Integer count, Boolean isShallow ) { Map< String, String > params = new HashMap< String, String >(); addNameToParamMap( params, name ); addOffsetToParamMap( params, offset, count ); addAuthTokenToParamMap( params ); addShallowToPramMap( params, isShallow ); return params; } /** * to get the parameter map by property values. * * @param property * @param values * @param offset * @param count * @return Map */ protected Map< String, String > getParamMapByPropertyValues( String property, String[] values, Integer offset, Integer count, Boolean isShallow ) { Map< String, String > params = new HashMap< String, String >(); addPropertyValuesToParamMap( params, property, values ); addOffsetToParamMap( params, offset, count ); addShallowToPramMap( params, isShallow ); return params; } /** * to get the parameter map by property values and token. * * @param property * @param values * @param offset * @param count * @param isShallow * @return Map */ protected Map< String, String > getParamMapByPropertyValuesAndToken( String property, String[] values, Integer offset, Integer count, Boolean isShallow ) { Map< String, String > params = new HashMap< String, String >(); addPropertyValuesToParamMap( params, property, values ); addOffsetToParamMap( params, offset, count ); addAuthTokenToParamMap( params ); addShallowToPramMap( params, isShallow ); return params; } /** * to get the parameter map by criteria. * * @param criteria * @param offset * @param count * @return Map */ protected Map< String, String > getParamMapByCriteria( Map< String, String > criteria, Integer offset, Integer count, Boolean isShallow ) { Map< String, String > params = new HashMap< String, String >(); addCriteriaToParamMap( params, criteria ); addOffsetToParamMap( params, offset, count ); addShallowToPramMap( params, isShallow ); return params; } /** * to get the parameter map by criteria and token. * * @param criteria * @param offset * @param count * @return Map */ protected Map< String, String > getParamMapByCriteriaAndToken( Map< String, String > criteria, Integer offset, Integer count, Boolean isShallow ) { Map< String, String > params = new HashMap< String, String >(); addCriteriaToParamMap( params, criteria ); addOffsetToParamMap( params, offset, count ); addAuthTokenToParamMap( params ); addShallowToPramMap( params, isShallow ); return params; } /** * to get the parameter map by offset and token. * * @param offset * @param count * @return Map */ protected Map< String, String > getParamMapByOffsetAndTocken( Integer offset, Integer count ) { Map< String, String > params = new HashMap< String, String >(); addOffsetToParamMap( params, offset, count ); addAuthTokenToParamMap( params ); return params; } protected Map< String, String > getParamMapByOffsetAndNoTocken( Integer offset, Integer count ) { Map< String, String > params = new HashMap< String, String >(); addOffsetToParamMap( params, offset, count ); return params; } private void addIdToParamMap( Map< String, String > params, String id ) { params.put( ID, id ); } private void addMacIdToParamMap( Map< String, String > params, String macId ) { params.put( MAC_ID, macId ); } private void addNameToParamMap( Map< String, String > params, String name ) { try { params.put( PROPERTY_NAME, URLEncoder.encode( name, UTF_8 ) ); } catch ( UnsupportedEncodingException e ) { e.printStackTrace(); } } private void addAuthTokenToParamMap( Map< String, String > params ) { params.put( AUTH_TOKEN, properties.getAuthToken() ); } private void addAuthTokenToParamMap( Map< String, String > params, String authToken ) { params.put( AUTH_TOKEN, authToken ); } private void addAllocationCategoryToParamMap( Map< String, String > params, String authToken ) { params.put( ALLOCATION_CATEGORY, authToken ); } private void addReacquireFlagToParamMap( Map< String, String > params, Boolean reacquire ) { params.put( REACQUIRE_FLAG, Boolean.toString( reacquire ) ); } private void addDurationToParamMap( Map< String, String > params, Integer duration ) { params.put( DURATION, Integer.toString( duration ) ); } private void addPropertyValuesToParamMap( Map< String, String > params, String property, String[] values ) { params.put( PROPERTY_NAME, property ); params.put( PROPERTY_VALUE, CommonUtil.arrayToString( values ) ); } private void addCriteriaToParamMap( Map< String, String > params, Map< String, String > criteria ) { params.put( CRITERIA, CommonUtil.mapToString( criteria ) ); } private void addShallowToPramMap( Map< String, String > params, Boolean isShallow ) { params.put( SHALLOW, Boolean.toString( isShallow ) ); } private void addOffsetToParamMap( Map< String, String > params, Integer offset, Integer count ) { if ( count > 0 ) { params.put( OFFSET, Integer.toString( offset ) ); params.put( COUNT, Integer.toString( count ) ); } } /** * To set the RestTemplate. mainly to support Testing * * @param restTemplate */ protected void setRestTemplate( RestTemplate restTemplate ) { this.restTemplateProducer.setRestTemplate( restTemplate ); } }