/** * Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT * All rights reserved. Use is subject to license terms. See LICENSE.TXT */ package org.diirt.service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import static org.diirt.service.Service.namePattern; /** * A utility class to gather all the elements that define the service. * <p> * This class is not thread-safe and is meant to be used right before the * creation of {@link Service} objects. * * @author carcassi */ public class ServiceDescription { // Access is package private so we don't even bother creating accessors for // these String name; String description; List<ServiceMethodDescription> serviceMethodDescriptions = new ArrayList<>(); ExecutorService executorService; /** * Creates a new service description with the given name and description, * both of which are mandatory attributes of the service. * * @param name the service name, can't be null * @param description the service description; can't be null */ public ServiceDescription(String name, String description) { // Validate the parameters (non-null and non-empty) if (name == null){ throw new NullPointerException("Name must not be null"); } if (description == null){ throw new NullPointerException("Description must not be null"); } if (name.isEmpty()){ throw new IllegalArgumentException("Name must not be empty"); } if (description.isEmpty()){ throw new IllegalArgumentException("Description must not be empty"); } this.name = name; this.description = description; if (!namePattern.matcher(name).matches()) { throw new IllegalArgumentException("Name must start by a letter and only consist of letters and numbers"); } } /** * Adds the given method to this service description. The name of the * given service method must be unique to the service (i.e. can't match the * name of an already added service method). * * @param serviceMethodDescription a service method description, can't be null * @return this description */ public ServiceDescription addServiceMethod(ServiceMethodDescription serviceMethodDescription) { // Validate parameters (non-null, non-duplicate method) if (serviceMethodDescription == null) { throw new NullPointerException("ServiceMethodDescription must not be null"); } // Throws exception if parameter has a duplicate name of a service method if (serviceMethodDescriptions.stream() .anyMatch(otherMethodDescription -> otherMethodDescription.name.equals(serviceMethodDescription.name))) { throw new IllegalArgumentException("ServiceMethodDescription with name \'" + serviceMethodDescription.name + "\' already exists"); } serviceMethodDescriptions.add(serviceMethodDescription); return this; } /** * Determines the executor to be used by the service. The executor * can't be changed once set. * <p> * The executor is used for wrapping synchronous calls into asynchronous * calls. * * @param executor an executor service, can't be null * @return this description */ public ServiceDescription executorService(ExecutorService executor) { // Validate parameters (non-null, not already set) if (executor == null) { throw new NullPointerException("ExecutorService must not be null"); } if (this.executorService != null) { throw new IllegalArgumentException("ExecutorService was already set"); } this.executorService = executor; return this; } /** * Creates the service method instances that belongs to this service. * * @return the new service methods indexed by method name */ public final Map<String, ServiceMethod> createServiceMethods() { Map<String, ServiceMethod> map = new HashMap<>(); for (ServiceMethodDescription serviceMethodDescription : serviceMethodDescriptions) { ServiceMethod method = serviceMethodDescription.createServiceMethod(this); map.put(method.getName(), method); } return map; } /** * Creates a service with the given description. * <p> * A client may override this to return their service * implementation. * * @return a service based off of this description state */ public Service createService() { return new Service(this); } }