/** * Copyright (C) 2015 Orange * 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 com.francetelecom.clara.cloud.techmodel.cf; import com.francetelecom.clara.cloud.commons.MavenReference; import com.francetelecom.clara.cloud.model.DependantModelItem; import com.francetelecom.clara.cloud.model.DeploymentStateEnum; import com.francetelecom.clara.cloud.model.XaasSubscription; import com.francetelecom.clara.cloud.techmodel.cf.services.managed.ManagedService; import com.francetelecom.clara.cloud.techmodel.cf.services.userprovided.AbstractUserProvidedService; import com.thoughtworks.xstream.annotations.XStreamImplicit; import org.apache.commons.lang3.builder.ToStringBuilder; import org.hibernate.annotations.ColumnDefault; import org.springframework.util.Assert; import javax.persistence.*; import javax.validation.Valid; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; import java.lang.reflect.Field; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; /** * an application */ @XmlRootElement @Entity public class App extends XaasSubscription { private String appName; @Embedded private MavenReference appBinaries; private String buildPackUrl; private String stack; @XmlElementWrapper @XmlElement(name = "route") @OneToMany(fetch = FetchType.EAGER) @Valid Set<Route> routes; /** * the space, the application is scoped to */ @XmlElement(name = "space") @OneToOne private Space space; /** * user provided services used by this app */ @ManyToMany(fetch = FetchType.EAGER) private Set<AbstractUserProvidedService> userProvidedServices; /** * managed services used by this app */ @ManyToMany(fetch = FetchType.EAGER) private Set<ManagedService> managedServices; private int ramMb = 256; private int instanceCount = 1; @ColumnDefault(value = "false") private boolean optionalApplicationBinaries = false; /** * The set of Env variables that would be made available in the cf app as * environement variables */ @XStreamImplicit(itemFieldName = "entry") @XmlElementWrapper @XmlElement(name = "entry") @ElementCollection(fetch = FetchType.EAGER) private Map<EnvVariableKey, EnvVariableValue> envVariables; private String externalReference; private int diskSizeMb = 1024; /** * constuctor for JPA Jaxb */ protected App() { } /** * Constructor with only mandatory arguments. Mainly used in tests * * @param space the space, the application is scoped to * @param appBinaries maven app binaries reference * @param appName the app name */ public App(Space space, MavenReference appBinaries, String appName) { super(); setAppName(appName); setAppBinaries(appBinaries); setSpace(space); this.routes = new HashSet<>(); this.userProvidedServices = new HashSet<>(); this.managedServices = new HashSet<>(); this.envVariables = new HashMap<>(); } public App(Space space, String appName, MavenReference appBinaries, String buildPackUrl, int ramMb, int instanceCount) { this(space, appBinaries, appName); setBuildPackUrl(buildPackUrl); setRamMb(ramMb); setInstanceCount(instanceCount); } public void activate(UUID externalId) { setDeploymentState(DeploymentStateEnum.CREATED); setExternalReference(externalId); } public void stop() { setDeploymentState(DeploymentStateEnum.STOPPED); } public void delete() { setDeploymentState(DeploymentStateEnum.REMOVED); } private void setBuildPackUrl(String buildPackUrl) { Assert.hasText(buildPackUrl, "Fail to set build pack url. build pack url value <" + buildPackUrl + "> is not valid."); this.buildPackUrl = buildPackUrl; } public String getBuildPackUrl() { return buildPackUrl; } public MavenReference getAppBinaries() { return appBinaries; } public int getRamMb() { return ramMb; } public String getAppName() { return appName; } private void setAppName(String appName) { Assert.hasText(appName, "Fail to set app name. app name <" + appName + ">is not valid."); this.appName = appName; } public int getInstanceCount() { return instanceCount; } public void updateAppBinaries(MavenReference resolvedAppBinaries) { appBinaries = resolvedAppBinaries; } public Set<Route> getRoutes() { return routes; } public List<String> getRouteURIs() { return routes.stream().map(Route::getUri).collect(Collectors.toList()); } /** * @param route CF uri to bind, or null to have no uri bound (e.g. * "webGui1-env1-paasinstance1.cfapps.io" or * "webGui1-env1-paasinstance1.cfapps.elpaaso.net") Those are the * FQDN of the app (which should be relative to the configured * subdomain or CF default subdomain) */ public void mapRoute(Route route) { Assert.notNull(route, "Fail to map route<" + route + "> to app<" + appName + ">. route is not valid."); this.routes.add(route); } public void bindService(AbstractUserProvidedService service) { Assert.notNull(service, "Fail to bind service<" + service + "> to app<" + appName + ">. service is not valid."); this.userProvidedServices.add(service); } public void bindService(ManagedService service) { Assert.notNull(service, "Fail to bind service<" + service + "> to app<" + appName + ">. service is not valid."); this.managedServices.add(service); } public List<String> getServiceNames() { return Stream.concat(userProvidedServices.stream().map(AbstractUserProvidedService::getServiceName), managedServices.stream().map(ManagedService::getServiceInstance)).collect(Collectors.toList()); } public String getExternalReference() { return externalReference; } private void setRamMb(int ramMb) { Assert.isTrue(ramMb > 0, "Fail to set app ram. ram value <" + ramMb + "> is not valid"); this.ramMb = ramMb; } private void setInstanceCount(int instanceCount) { Assert.isTrue(instanceCount >= 1, "Fail to set app instance count <" + instanceCount + ">. At least one instance is required."); this.instanceCount = instanceCount; } private void setExternalReference(UUID externalReference) { Assert.notNull(externalReference, "Fail to reference cloud foundry app uid. app uid <" + externalReference + ">is not valid."); this.externalReference = externalReference.toString(); } private void setAppBinaries(MavenReference appBinaries) { Assert.notNull(appBinaries, "Fail to set app binaries. app binaries value <" + appBinaries + "> is not valid."); this.appBinaries = appBinaries; } public SpaceName getSpace() { return space.getSpaceName(); } public void setSpace(Space space) { Assert.notNull(space, "unable to scope service <" + appName + "> to space <" + space + ">. invalid space."); this.space = space; } /** * List currently env variables * * @return a non modifiable list */ public Map<EnvVariableKey, EnvVariableValue> listEnvVariables() { return Collections.unmodifiableMap(this.envVariables); } public String getEnvVarValue(String key) { EnvVariableValue envVariableValue = envVariables.get(new EnvVariableKey(key)); if (envVariableValue == null) { return null; } return envVariableValue.getValue(); } public void setEnvVariable(String key, String value) { envVariables.put(new EnvVariableKey(key), new EnvVariableValue(value)); } @Override public Set<DependantModelItem> listDepedencies() { Set<DependantModelItem> dependantModelItems = new HashSet<>(); Field[] fields = this.getClass().getDeclaredFields(); for (Field field : fields) { if (XaasSubscription.class.isAssignableFrom(field.getType())) { try { XaasSubscription xaasSubscription = XaasSubscription.class.cast(field.get(this)); dependantModelItems.add(xaasSubscription); dependantModelItems.addAll(xaasSubscription.listDepedencies()); } catch (IllegalArgumentException | IllegalAccessException e) { throw new RuntimeException(e); } } else { if (Collection.class.isAssignableFrom(field.getType())) { Collection collections; try { collections = Collection.class.cast(field.get(this)); } catch (IllegalArgumentException | IllegalAccessException e) { throw new RuntimeException(e); } for (Object object : collections) { if (XaasSubscription.class.isAssignableFrom(object.getClass())) { try { XaasSubscription xaasSubscription = XaasSubscription.class.cast(object); dependantModelItems.add(xaasSubscription); dependantModelItems.addAll(xaasSubscription.listDepedencies()); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } } } } } } return dependantModelItems; } public String toString() { return ToStringBuilder.reflectionToString(this); } public boolean isOptionalApplicationBinaries() { return optionalApplicationBinaries; } public void setOptionalApplicationBinaries(boolean optionalApplicationBinaries) { this.optionalApplicationBinaries = optionalApplicationBinaries; } public boolean isStopped() { return DeploymentStateEnum.STOPPED.equals(getDeploymentState()); } public String getStack() { return stack; } public void setStack(String stack) { this.stack = stack; } public void setDiskSizeMb(int diskSize) { Assert.isTrue(diskSize > 0, "Disk size should be greater than 0. <" + diskSize + ">is not valid."); this.diskSizeMb = diskSize; } public int getDiskSizeMb() { return diskSizeMb; } }