blob: b8426f0dcdef207028e5e335d2e89744d3bea852 [file] [log] [blame]
/*
* Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.loadbalancer.config;
import org.glassfish.loadbalancer.config.customvalidators.RefConstraint;
import org.glassfish.loadbalancer.config.customvalidators.RefValidator;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.beans.PropertyVetoException;
import com.sun.enterprise.util.LocalStringManagerImpl;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.config.serverbeans.Ref;
import com.sun.enterprise.config.serverbeans.ServerRef;
import com.sun.enterprise.config.serverbeans.ClusterRef;
import com.sun.logging.LogDomains;
import java.util.Date;
import org.glassfish.config.support.*;
import org.glassfish.quality.ToDo;
import org.jvnet.hk2.annotations.Service;
import org.glassfish.hk2.api.PerLookup;
import org.jvnet.hk2.config.*;
import org.jvnet.hk2.config.types.Property;
import org.jvnet.hk2.config.types.PropertyBag;
import org.glassfish.api.Param;
import org.glassfish.api.admin.AdminCommandContext;
import org.glassfish.api.admin.config.PropertiesDesc;
import jakarta.inject.Inject;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Pattern;
import static org.glassfish.config.support.Constants.*;
import jakarta.validation.Payload;
/**
*
*/
/* @XmlType(name = "", propOrder = {
"clusterRefOrServerRef",
"property"
}) */
@Configured
@RefConstraint(message="{ref.invalid}", payload= RefValidator.class)
public interface LbConfig extends ConfigBeanProxy, PropertyBag, Payload {
String LAST_APPLIED_PROPERTY = "last-applied";
String LAST_EXPORTED_PROPERTY = "last-exported";
/**
* Gets the value of the name property.
*
* Name of the load balancer configuration
*
* @return possible object is
* {@link String }
*/
@Attribute(key=true)
@Pattern(regexp=NAME_REGEX, message="{lbconfig.invalid.name}", payload=LbConfig.class)
@NotNull
String getName();
/**
* Sets the value of the name property.
*
* @param value allowed object is
* {@link String }
*/
@Param (name = "name", primary=true)
void setName(String value) throws PropertyVetoException;
/**
* Gets the value of the responseTimeoutInSeconds property.
*
* Period within which a server must return a response or otherwise it will
* be considered unhealthy. Default value is 60 seconds. Must be greater
* than or equal to 0. A value of 0 effectively turns off this check
* functionality, meaning the server will always be considered healthy
*
* @return possible object is
* {@link String }
*/
@Attribute (defaultValue="60")
@Min(value=0)
String getResponseTimeoutInSeconds();
/**
* Sets the value of the responseTimeoutInSeconds property.
*
* @param value allowed object is
* {@link String }
*/
@Param(name = "responsetimeout", optional=true)
void setResponseTimeoutInSeconds(String value) throws PropertyVetoException;
/**
* Gets the value of the httpsRouting property.
*
* Boolean flag indicating how load-balancer will route https requests.
* If true then an https request to the load-balancer will result in an
* https request to the server; if false then https requests to the
* load-balancer result in http requests to the server.
* Default is to use http (i.e. value of false)
*
* @return possible object is
* {@link String }
*/
@Attribute (defaultValue="false",dataType=Boolean.class)
String getHttpsRouting();
/**
* Sets the value of the httpsRouting property.
*
* @param value allowed object is
* {@link String }
*/
@Param(name = "httpsrouting", optional=true)
void setHttpsRouting(String value) throws PropertyVetoException;
/**
* Gets the value of the reloadPollIntervalInSeconds property.
*
* Maximum period, in seconds, that a change to the load balancer
* configuration file takes before it is detected by the load balancer and
* the file reloaded. A value of 0 indicates that reloading is disabled.
* Default period is 1 minute (60 sec)
*
* @return possible object is
* {@link String }
*/
@Attribute (defaultValue="60")
String getReloadPollIntervalInSeconds();
/**
* Sets the value of the reloadPollIntervalInSeconds property.
*
* @param value allowed object is
* {@link String }
*/
@Param(name = "reloadinterval", optional=true)
void setReloadPollIntervalInSeconds(String value) throws PropertyVetoException;
/**
* Gets the value of the monitoringEnabled property.
*
* Boolean flag that determines whether monitoring is switched on or not.
* Default is that monitoring is switched off (false)
*
* @return possible object is
* {@link String }
*/
@Attribute (defaultValue="false",dataType=Boolean.class)
String getMonitoringEnabled();
/**
* Sets the value of the monitoringEnabled property.
*
* @param value allowed object is
* {@link String }
*/
@Param(name = "monitor", optional=true)
void setMonitoringEnabled(String value) throws PropertyVetoException;
/**
* Gets the value of the routeCookieEnabled property.
*
* Boolean flag that determines whether a route cookie is or is not enabled.
* Default is enabled (true).
*
* @return possible object is
* {@link String }
*/
@Attribute (defaultValue="true",dataType=Boolean.class)
String getRouteCookieEnabled();
/**
* Sets the value of the routeCookieEnabled property.
*
* @param value allowed object is
* {@link String }
*/
@Param(name = "routecookie", optional=true)
void setRouteCookieEnabled(String value) throws PropertyVetoException;
/**
* Gets the value of the clusterRefOrServerRef property.
* <p/>
* <p/>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the clusterRefOrServerRef property.
* <p/>
* <p/>
* For example, to add a new item, do as follows:
* <pre>
* getClusterRefOrServerRef().add(newItem);
* </pre>
* <p/>
* <p/>
* <p/>
* Objects of the following type(s) are allowed in the list
* {@link ClusterRef }
* {@link ServerRef }
*/
@Element("*")
List<Ref> getClusterRefOrServerRef();
/**
Properties as per {@link PropertyBag}
*/
@Override
@ToDo(priority=ToDo.Priority.IMPORTANT, details="Provide PropertyDesc for legal props" )
@PropertiesDesc(props={})
@Element
List<Property> getProperty();
@DuckTyped
<T> List<T> getRefs(Class<T> type);
@DuckTyped
<T> T getRefByRef(Class<T> type, String ref);
@DuckTyped
Date getLastExported();
@DuckTyped
Date getLastApplied();
@DuckTyped
boolean setLastExported();
@DuckTyped
boolean setLastApplied();
public class Duck {
public static <T> List<T> getRefs(LbConfig lc, Class<T> type) {
List<T> refs = new ArrayList<T>();
for (Object r : lc.getClusterRefOrServerRef()) {
if (type.isInstance(r)) {
refs.add(type.cast(r));
}
}
// you have to return an umodifiable list since this list
// is not the real list of elements as maintained by this config bean
return Collections.unmodifiableList(refs);
}
public static <T> T getRefByRef(LbConfig lc, Class<T> type, String ref) {
if (ref == null) {
return null;
}
for (Ref r : lc.getClusterRefOrServerRef())
if (type.isInstance(r) && r.getRef().equals(ref))
return type.cast(r);
return null;
}
public static Date getLastExported(LbConfig lc) {
return getInternalPropertyValue(lc, LAST_EXPORTED_PROPERTY);
}
public static Date getLastApplied(LbConfig lc) {
return getInternalPropertyValue(lc, LAST_APPLIED_PROPERTY);
}
private static Date getInternalPropertyValue(LbConfig lc,
String propertyName) {
String propertyValue = lc.getPropertyValue(propertyName);
if(propertyValue == null){
return null;
}
return new Date(Long.parseLong(propertyValue));
}
public static boolean setLastExported(LbConfig lc) {
return setInternalProperty(lc, LAST_EXPORTED_PROPERTY);
}
public static boolean setLastApplied(LbConfig lc) {
return setInternalProperty(lc, LAST_APPLIED_PROPERTY);
}
private static boolean setInternalProperty(LbConfig lc,
String propertyName) {
Property property = lc.getProperty(propertyName);
Transaction transaction = new Transaction();
try {
if (property == null) {
ConfigBeanProxy lcProxy = transaction.enroll(lc);
property = lcProxy.createChild(Property.class);
property.setName(propertyName);
property.setValue(String.valueOf((new Date()).getTime()));
((LbConfig)lcProxy).getProperty().add(property);
} else {
ConfigBeanProxy propertyProxy = transaction.enroll(property);
((Property)propertyProxy).setValue(String.valueOf(
(new Date()).getTime()));
}
transaction.commit();
} catch (Exception ex) {
transaction.rollback();
Logger logger = LogDomains.getLogger(LbConfig.class,
LogDomains.ADMIN_LOGGER);
LocalStringManagerImpl localStrings =
new LocalStringManagerImpl(LbConfig.class);
String msg = localStrings.getLocalString(
"UnableToSetPropertyInLbconfig",
"Unable to set property {0} in lbconfig with name {1}",
new String[]{propertyName, lc.getName()});
logger.log(Level.SEVERE, msg);
logger.log(Level.FINE, "Exception when trying to set property "
+ propertyName + " in lbconfig " + lc.getName(), ex);
return false;
}
return true;
}
}
@Service
@PerLookup
class Decorator implements CreationDecorator<LbConfig> {
@Param (name = "name", optional=true)
String config_name;
@Param(optional=true)
String target;
@Param (optional=true, defaultValue="60")
String responsetimeout;
@Param (optional=true, defaultValue="false")
Boolean httpsrouting;
@Param (optional=true, defaultValue="60")
String reloadinterval;
@Param (optional=true, defaultValue="false")
Boolean monitor;
@Param (optional=true, defaultValue="true")
Boolean routecookie;
@Param(optional=true, name="property", separator=':')
Properties properties;
@Inject
Domain domain;
/**
* Create lb-config entries
* tasks :
* - ensures that it references an existing cluster
* @param context administration command context
* @param instance newly created configuration element
* @throws TransactionFailure
* @throws PropertyVetoException
*
*/
@Override
public void decorate(AdminCommandContext context, final LbConfig instance) throws TransactionFailure, PropertyVetoException {
Logger logger = LogDomains.getLogger(LbConfig.class, LogDomains.ADMIN_LOGGER);
LocalStringManagerImpl localStrings = new LocalStringManagerImpl(LbConfig.class);
if (config_name == null && target == null) {
String msg = localStrings.getLocalString("RequiredTargetOrConfig", "Neither LB config name nor target specified");
throw new TransactionFailure(msg);
}
// generate lb config name if not specified
if (config_name == null) {
config_name = target + "_LB_CONFIG";
}
LbConfigs lbconfigs = domain.getExtensionByType(LbConfigs.class);
//create load-balancers parent element if it does not exist
if (lbconfigs == null) {
Transaction transaction = new Transaction();
try {
ConfigBeanProxy domainProxy = transaction.enroll(domain);
lbconfigs = domainProxy.createChild(LbConfigs.class);
((Domain) domainProxy).getExtensions().add(lbconfigs);
transaction.commit();
} catch (TransactionFailure ex) {
transaction.rollback();
String msg = localStrings.getLocalString("LbConfigsCreationFailed", "Creation of parent element lb-configs failed");
throw new TransactionFailure(msg, ex);
} catch (RetryableException ex) {
transaction.rollback();
String msg = localStrings.getLocalString("LbConfigsCreationFailed", "Creation of parent element lb-configs failed");
throw new TransactionFailure(msg, ex);
}
}
if (lbconfigs.getLbConfig(config_name) != null) {
String msg = localStrings.getLocalString("LbConfigExists", config_name);
throw new TransactionFailure(msg);
}
instance.setName(config_name);
instance.setResponseTimeoutInSeconds(responsetimeout);
instance.setReloadPollIntervalInSeconds(reloadinterval);
instance.setMonitoringEnabled(monitor==null ? null : monitor.toString());
instance.setRouteCookieEnabled(routecookie==null ? null : routecookie.toString());
instance.setHttpsRouting(httpsrouting==null ? null : httpsrouting.toString());
// creates a reference to the target
if (target != null) {
if (domain.getClusterNamed(target) != null) {
ClusterRef cRef = instance.createChild(ClusterRef.class);
cRef.setRef(target);
instance.getClusterRefOrServerRef().add(cRef);
} else if (domain.isServer(target)) {
ServerRef sRef = instance.createChild(ServerRef.class);
sRef.setRef(target);
instance.getClusterRefOrServerRef().add(sRef);
} else {
String msg = localStrings.getLocalString("InvalidTarget", target);
throw new TransactionFailure(msg);
}
}
// add properties
if (properties != null) {
for (Object propname: properties.keySet()) {
Property newprop = instance.createChild(Property.class);
newprop.setName((String) propname);
newprop.setValue(properties.getProperty((String) propname));
instance.getProperty().add(newprop);
}
}
logger.info(localStrings.getLocalString("http_lb_admin.LbConfigCreated",
"Load balancer configuration {0} created.", config_name));
}
}
@Service
@PerLookup
class DeleteDecorator implements DeletionDecorator<LbConfigs, LbConfig> {
@Inject
private Domain domain;
@Override
public void decorate(AdminCommandContext context, LbConfigs parent, LbConfig child)
throws PropertyVetoException, TransactionFailure {
Logger logger = LogDomains.getLogger(LbConfig.class, LogDomains.ADMIN_LOGGER);
LocalStringManagerImpl localStrings = new LocalStringManagerImpl(LbConfig.class);
String lbConfigName = child.getName();
LbConfig lbConfig = domain.getExtensionByType(LbConfigs.class).getLbConfig(lbConfigName);
//Ensure there are no refs
if ( (lbConfig.getClusterRefOrServerRef().size() != 0 ) ) {
String msg = localStrings.getLocalString("LbConfigNotEmpty", lbConfigName);
throw new TransactionFailure(msg);
}
logger.info(localStrings.getLocalString("http_lb_admin.LbConfigDeleted", lbConfigName));
}
}
}