/*************************************************************************
* Copyright 2009-2014 Eucalyptus Systems, Inc.
*
* This program 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; version 3 of the License.
*
* This program 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 this program. If not, see http://www.gnu.org/licenses/.
*
* Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
* CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
* additional information or have any questions.
************************************************************************/
package com.eucalyptus.loadbalancing;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.NoSuchElementException;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PersistenceContext;
import javax.persistence.PostLoad;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.apache.log4j.Logger;
import com.eucalyptus.crypto.util.PEMFiles;
import com.eucalyptus.entities.AbstractPersistent;
import com.eucalyptus.entities.Entities;
import com.eucalyptus.entities.TransactionResource;
import com.eucalyptus.loadbalancing.LoadBalancerBackendServerDescription.LoadBalancerBackendServerDescriptionCoreView;
import com.eucalyptus.loadbalancing.LoadBalancerBackendServerDescription.LoadBalancerBackendServerDescriptionCoreViewTransform;
import com.eucalyptus.loadbalancing.LoadBalancerListener.LoadBalancerListenerCoreView;
import com.eucalyptus.loadbalancing.LoadBalancerListener.LoadBalancerListenerCoreViewTransform;
import com.eucalyptus.loadbalancing.LoadBalancerPolicyAttributeDescription.LoadBalancerPolicyAttributeDescriptionCoreView;
import com.eucalyptus.loadbalancing.LoadBalancerPolicyAttributeDescription.LoadBalancerPolicyAttributeDescriptionCoreViewTransform;
import com.eucalyptus.loadbalancing.LoadBalancerPolicyAttributeDescription.LoadBalancerPolicyAtttributeDescriptionEntityTransform;
import com.eucalyptus.loadbalancing.LoadBalancerPolicyAttributeTypeDescription.LoadBalancerPolicyAttributeTypeDescriptionCoreView;
import com.eucalyptus.loadbalancing.service.InvalidConfigurationRequestException;
import com.eucalyptus.util.EucalyptusCloudException;
import com.eucalyptus.util.Exceptions;
import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
@Entity
@PersistenceContext( name = "eucalyptus_loadbalancing" )
@Table( name = "metadata_policy_description" )
public class LoadBalancerPolicyDescription extends AbstractPersistent {
private static Logger LOG = Logger.getLogger( LoadBalancerPolicyDescription.class );
@Transient
private static final long serialVersionUID = 1L;
@Transient
private LoadBalancerPolicyDescriptionRelationView view = null;
@ManyToOne
@JoinColumn( name = "metadata_loadbalancer_fk", nullable=false )
private LoadBalancer loadbalancer = null;
@ManyToMany( fetch = FetchType.LAZY, mappedBy="policies")
private List<LoadBalancerListener> listeners = null;
@ManyToMany( fetch = FetchType.LAZY, mappedBy="policyDescriptions" )
private List<LoadBalancerBackendServerDescription> backendServers = null;
@Column( name = "policy_name", nullable=false)
private String policyName = null;
@Column( name = "policy_type_name", nullable=true)
private String policyTypeName = null;
@Column( name = "unique_name", unique=true, nullable=false)
private String uniqueName = null;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "policyDescription")
private List<LoadBalancerPolicyAttributeDescription> policyAttrDescription = null;
@Transient
private LoadBalancerPolicyTypeDescription policyType = null;
private LoadBalancerPolicyDescription(){}
private LoadBalancerPolicyDescription(final LoadBalancer lb, final String policyName){
this.loadbalancer = lb;
this.policyName = policyName;
}
public LoadBalancerPolicyDescription(final LoadBalancer lb, final String policyName, final String policyTypeName){
this(lb, policyName);
this.policyTypeName = policyTypeName;
}
public LoadBalancerPolicyDescription(final LoadBalancer lb, final String policyName,
final String policyTypeName, final List<LoadBalancerPolicyAttributeDescription> descs){
this(lb, policyName, policyTypeName);
this.policyAttrDescription = descs;
}
public static LoadBalancerPolicyDescription named(final LoadBalancer lb, final String policyName){
final LoadBalancerPolicyDescription instance = new LoadBalancerPolicyDescription(lb, policyName);
instance.uniqueName = instance.createUniqueName();
return instance;
}
public String getPolicyName(){
return this.policyName;
}
public String getPolicyTypeName(){
return this.policyTypeName;
}
public LoadBalancerPolicyTypeDescription getPolicyTypeDescription(){
if(this.policyType == null){
this.policyType = LoadBalancerPolicies.findLoadBalancerPolicyTypeDescription(this.policyTypeName);
}
return this.policyType;
}
public void addPolicyAttributeDescription(final String attrName, String attrValue)
throws InvalidConfigurationRequestException {
if(this.getPolicyTypeDescription() != null){
LoadBalancerPolicyAttributeTypeDescriptionCoreView attrType = null;
for(final LoadBalancerPolicyAttributeTypeDescriptionCoreView type: this.policyType.getPolicyAttributeTypeDescriptions()){
if(attrName.equals(type.getAttributeName())){
attrType = type;
break;
}
}
if(attrType==null)
throw new InvalidConfigurationRequestException(String.format("Attribute %s is not defined in the policy type", attrName));
if(!LoadBalancerPolicies.isAttributeValueValid(attrType.getAttributeType(), attrType.getCardinality(), attrValue))
throw new InvalidConfigurationRequestException(String.format("Attribute value %s is not valid", attrValue));
/* check for cardinality
* ONE(1) : Single value required
ZERO_OR_ONE(0..1) : Up to one value can be supplied
ZERO_OR_MORE(0..*) : Optional. Multiple values are allowed
ONE_OR_MORE(1..*0) : Required. Multiple values are allowed
*/
final String cardinality = attrType.getCardinality();
if(this.policyAttrDescription != null && ("ONE".equals(cardinality) || "ZERO_OR_ONE".equals(cardinality))) {
for(final LoadBalancerPolicyAttributeDescription existing : this.policyAttrDescription) {
if(attrName.equals(existing.getAttributeName()))
throw new InvalidConfigurationRequestException(String.format("More than one attribute(%s) is found (Cardinality: %s)", attrName, cardinality));
}
}
if ("PublicKeyPolicyType".equals(this.policyType.getPolicyTypeName()) &&
"PublicKey".equals(attrName)) {
try{
String certString = attrValue.trim();
if(! certString.startsWith("-----BEGIN CERTIFICATE-----"))
certString = String.format("-----BEGIN CERTIFICATE-----\n%s", certString);
if(! certString.endsWith("-----END CERTIFICATE-----"))
certString = String.format("%s\n-----END CERTIFICATE-----", certString);
final X509Certificate cert = PEMFiles.getCert(certString.getBytes( Charsets.UTF_8 ));
if(cert==null)
throw new EucalyptusCloudException("Malformed cert");
attrValue = certString;
}catch(final Exception ex){
throw new InvalidConfigurationRequestException("PublicKey is invalid");
}
}
}
final LoadBalancerPolicyAttributeDescription attr = new LoadBalancerPolicyAttributeDescription(this, attrName, attrValue);
if(this.policyAttrDescription == null)
this.policyAttrDescription = Lists.newArrayList();
this.policyAttrDescription.add(attr);
}
public void removePolicyAttributeDescription(final LoadBalancerPolicyAttributeDescription desc){
if(this.policyAttrDescription == null)
return;
this.policyAttrDescription.remove(desc);
}
public List<LoadBalancerPolicyAttributeDescriptionCoreView> getPolicyAttributeDescription(){
return this.view.getPolicyAttributeDescription();
}
public List<LoadBalancerPolicyAttributeDescription> findAttributeDescription(final String attrName) throws NoSuchElementException{
final List<LoadBalancerPolicyAttributeDescription> attributes = Lists.newArrayList();
for (final LoadBalancerPolicyAttributeDescriptionCoreView attrView : this.getPolicyAttributeDescription()){
if(attrView.getAttributeName().equals(attrName)) {
attributes.add(LoadBalancerPolicyAtttributeDescriptionEntityTransform.INSTANCE.apply(attrView));
}
}
return attributes;
}
public List<LoadBalancerListenerCoreView> getListeners(){
return this.view.getListeners();
}
public List<LoadBalancerBackendServerDescriptionCoreView> getBackendServers(){
return this.view.getBackendServers();
}
@PostLoad
private void onLoad(){
if(this.view==null)
this.view = new LoadBalancerPolicyDescriptionRelationView(this);
}
@PrePersist
private void generateOnCommit( ) {
if(this.uniqueName==null)
this.uniqueName = createUniqueName( );
}
protected String createUniqueName( ) {
return String.format("policy-%s-%s-%s", this.loadbalancer.getOwnerAccountNumber(), this.loadbalancer.getDisplayName(), this.policyName);
}
public String getUniqueName(){
return this.uniqueName;
}
@Override
public boolean equals(final Object obj){
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass( ) != obj.getClass( ) ) {
return false;
}
final LoadBalancerPolicyDescription other = (LoadBalancerPolicyDescription) obj;
if(this.loadbalancer==null){
if( other.loadbalancer!=null){
return false;
}
}else if(!this.loadbalancer.equals(other.loadbalancer)){
return false;
}
if ( this.policyName == null ) {
if ( other.policyName != null ) {
return false;
}
} else if ( !this.policyName.equals( other.policyName ) ) {
return false;
}
return true;
}
public final String getRecordId(){
return this.getId();
}
@Override
public int hashCode(){
final int prime = 31;
int result = 1;
result = prime * result + ( ( this.loadbalancer == null )
? 0
: this.loadbalancer.hashCode( ) );
result = prime * result + ( ( this.policyName == null )
? 0
: this.policyName.hashCode( ) );
return result;
}
@Override
public String toString(){
return String.format("LoadBalancer Policy Description for (%s):%s-%s", this.loadbalancer, this.policyName, this.policyTypeName);
}
public static class LoadBalancerPolicyDescriptionRelationView{
private LoadBalancerPolicyDescription policyDesc = null;
private ImmutableList<LoadBalancerPolicyAttributeDescriptionCoreView> policyAttrDesc = null;
private ImmutableList<LoadBalancerListenerCoreView> listeners = null;
private ImmutableList<LoadBalancerBackendServerDescriptionCoreView> backendServers = null;
LoadBalancerPolicyDescriptionRelationView(final LoadBalancerPolicyDescription desc){
this.policyDesc = desc;
if(desc.policyAttrDescription != null)
this.policyAttrDesc = ImmutableList.copyOf(Collections2.transform(desc.policyAttrDescription,
LoadBalancerPolicyAttributeDescriptionCoreViewTransform.INSTANCE));
if(desc.listeners!= null)
this.listeners = ImmutableList.copyOf(Collections2.transform(desc.listeners,
LoadBalancerListenerCoreViewTransform.INSTANCE));
if(desc.backendServers!=null)
this.backendServers = ImmutableList.copyOf(Collections2.transform(desc.backendServers,
LoadBalancerBackendServerDescriptionCoreViewTransform.INSTANCE));
}
public ImmutableList<LoadBalancerPolicyAttributeDescriptionCoreView> getPolicyAttributeDescription(){
return this.policyAttrDesc;
}
public ImmutableList<LoadBalancerListenerCoreView> getListeners(){
return this.listeners;
}
public ImmutableList<LoadBalancerBackendServerDescriptionCoreView> getBackendServers(){
return this.backendServers;
}
}
public static class LoadBalancerPolicyDescriptionCoreView {
private LoadBalancerPolicyDescription policyDesc = null;
LoadBalancerPolicyDescriptionCoreView(final LoadBalancerPolicyDescription desc){
this.policyDesc = desc;
}
public String getPolicyName(){
return this.policyDesc.policyName;
}
public String getPolicyTypeName(){
return this.policyDesc.policyTypeName;
}
}
public enum LoadBalancerPolicyDescriptionCoreViewTransform implements
Function<LoadBalancerPolicyDescription, LoadBalancerPolicyDescriptionCoreView>{
INSTANCE;
@Override
public LoadBalancerPolicyDescriptionCoreView apply(
LoadBalancerPolicyDescription arg0) {
return new LoadBalancerPolicyDescriptionCoreView(arg0);
}
}
public enum LoadBalancerPolicyDescriptionEntityTransform implements
Function<LoadBalancerPolicyDescriptionCoreView, LoadBalancerPolicyDescription>{
INSTANCE;
@Override
public LoadBalancerPolicyDescription apply(
LoadBalancerPolicyDescriptionCoreView arg0) {
try ( final TransactionResource db = Entities.transactionFor( LoadBalancerPolicyDescription.class ) ) {
return Entities.uniqueResult(arg0.policyDesc);
}catch(final NoSuchElementException ex){
throw ex;
}catch (final Exception ex) {
throw Exceptions.toUndeclared(ex);
}
}
}
}