/*
* Copyright (c) 2014 Globo.com - ATeam
* All rights reserved.
*
* This source is subject to the Apache License, Version 2.0.
* Please see the LICENSE file for more information.
*
* Authors: See AUTHORS file
*
* 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.globo.galeb.entity.impl.backend;
import org.vertx.java.core.json.JsonArray;
import org.vertx.java.core.json.JsonObject;
import com.globo.galeb.criteria.ICriterion;
import com.globo.galeb.criteria.impl.LoadBalanceCriterion;
import com.globo.galeb.entity.EntitiesMap;
import com.globo.galeb.entity.Entity;
import com.globo.galeb.request.RequestData;
import com.globo.galeb.rulereturn.IRuleReturn;
/**
* Class BackendPool.
*
* @author See AUTHORS file.
* @version 1.0.0, Nov 6, 2014.
*/
public class BackendPool extends EntitiesMap<IBackend> implements IRuleReturn {
/** The Constant BACKENDS_FIELDNAME. */
public static final String BACKENDS_FIELDNAME = "backends";
/** The Constant REQUEST_TIMEOUT_FIELDNAME. */
public static final String REQUEST_TIMEOUT_FIELDNAME = "requestTimeOut";
/** The Constant ENABLE_CHUNCKED_FIELDNAME. */
public static final String ENABLE_CHUNCKED_FIELDNAME = "enableChunked";
/** The Constant ENABLE_ACCESSLOG_FIELDNAME. */
public static final String ENABLE_ACCESSLOG_FIELDNAME = "enableAccessLog";
/** The Constant HEALTHCHECK_FIELDNAME. */
public static final String HEALTHCHECK_FIELDNAME = "healthCheck";
/** The rule return type. */
private final String returnType = BackendPool.class.getSimpleName();
/** The bad backends. */
private final EntitiesMap<IBackend> badBackends = new BadBackendPool("badbackends");
/** The load balance policy. */
private ICriterion<IBackend> loadBalanceCriterion = new LoadBalanceCriterion<IBackend>();
/** The request time out. */
private Long requestTimeOut = 60000L;
/** The max pool size. */
private int maxPoolSize = 1;
/** The keep alive max request. */
private long keepAliveMaxRequest = Long.MAX_VALUE;
/** The keep alive time out. */
private long keepAliveTimeOut = 86400000L;
/** The enable chunked. */
private boolean enableChunked = true;
/** The enable access log. */
private boolean enableAccessLog = false;
/** The min session pool size. */
private int minSessionPoolSize = 1;
/** The keep alive. */
private boolean keepAlive = true;
/** The max conn. */
private int maxConn = 0;
/**
* Instantiates a new backend pool.
*/
public BackendPool() {
super();
this.status = StatusType.RUNNING_STATUS;
}
/**
* Instantiates a new backend pool.
*
* @param id the id
*/
public BackendPool(String id) {
super(id);
this.status = StatusType.RUNNING_STATUS;
this.maxConn = (int) getOrCreateProperty(IBackend.MAXCONN_FIELDNAME, 0);
}
/**
* Instantiates a new backend pool.
*
* @param json the json
*/
public BackendPool(JsonObject json) {
super(json);
this.status = StatusType.RUNNING_STATUS;
this.maxConn = (int) getOrCreateProperty(IBackend.MAXCONN_FIELDNAME, 0);
}
/* (non-Javadoc)
* @see com.globo.galeb.rules.IRuleReturn#getReturnType()
*/
@Override
public String getReturnType() {
return returnType;
}
/* (non-Javadoc)
* @see com.globo.galeb.rules.IRuleReturn#getReturnId()
*/
@Override
public String getReturnId() {
return id;
}
/**
* Gets the choice.
*
* @param requestData the request data
* @return backend
*/
public IBackend getChoice(RequestData requestData) {
keepAlive = requestData.getKeepAlive();
requestData.getProperties().mergeIn(properties);
return loadBalanceCriterion.setLog(logger)
.given(getEntities())
.when(requestData)
.thenGetResult();
}
/**
* Reset load balance.
*
* @return this
*/
public BackendPool resetLoadBalance() {
loadBalanceCriterion.action(ICriterion.CriterionAction.RESET_REQUIRED);
return this;
}
/* (non-Javadoc)
* @see com.globo.galeb.core.entity.EntitiesMap#addEntity(com.globo.galeb.core.entity.Entity)
*/
@Override
public boolean addEntity(IBackend backend) {
((IBackend) ((Entity) backend.setMaxPoolSize(maxPoolSize)
.setKeepAlive(keepAlive)
.setKeepAliveMaxRequest(keepAliveMaxRequest)
.setKeepAliveTimeOut(keepAliveTimeOut)
.setMinSessionPoolSize(minSessionPoolSize))
.setStatus(StatusType.RUNNING_STATUS))
.setMaxConn(maxConn)
.startSessionPool();
resetLoadBalance();
return super.addEntity(backend);
}
/* (non-Javadoc)
* @see com.globo.galeb.core.entity.EntitiesMap#removeEntity(com.globo.galeb.core.entity.Entity)
*/
@Override
public boolean removeEntity(IBackend backend) {
backend.closeAllForced();
resetLoadBalance();
return super.removeEntity(backend);
}
/* (non-Javadoc)
* @see com.globo.galeb.core.entity.EntitiesMap#clearEntities()
*/
@Override
public void clearEntities() {
for (IBackend backend: getEntities().values()) {
backend.closeAllForced();
}
resetLoadBalance();
super.clearEntities();
}
/* (non-Javadoc)
* @see com.globo.galeb.core.entity.Entity#toJson()
*/
@Override
public JsonObject toJson() {
properties.putNumber(REQUEST_TIMEOUT_FIELDNAME, requestTimeOut);
properties.putNumber(IBackend.MAXPOOL_SIZE_FIELDNAME, maxPoolSize);
properties.putNumber(IBackend.KEEPALIVE_MAXREQUEST_FIELDNAME, keepAliveMaxRequest);
properties.putNumber(IBackend.KEEPALIVE_TIMEOUT_FIELDNAME, keepAliveTimeOut);
properties.putNumber(IBackend.MIN_SESSION_POOL_SIZE_FIELDNAME, minSessionPoolSize);
if (!properties.containsField(LoadBalanceCriterion.LOADBALANCE_POLICY_FIELDNAME)) {
properties.putString(LoadBalanceCriterion.LOADBALANCE_POLICY_FIELDNAME, LoadBalanceCriterion.LOADBALANCE_POLICY_DEFAULT);
}
if (!properties.containsField(BackendPool.HEALTHCHECK_FIELDNAME)) {
properties.putString(BackendPool.HEALTHCHECK_FIELDNAME, "/");
}
prepareJson();
JsonArray backendsJson = new JsonArray();
for (IBackend backend: getEntities().values()) {
backendsJson.addObject(backend.toJson());
}
for (IBackend backend: getBadBackends().getEntities().values()) {
((Entity) backend).setStatus(StatusType.FAILED_STATUS);
backendsJson.addObject(backend.toJson());
}
idObj.putArray(BACKENDS_FIELDNAME, backendsJson);
return super.toJson();
}
/* (non-Javadoc)
* @see com.globo.galeb.entity.Entity#setStaticConf(org.vertx.java.core.json.JsonObject)
*/
@Override
public BackendPool setStaticConf(JsonObject staticConf) {
super.setStaticConf(staticConf);
requestTimeOut = this.staticConf.getLong(REQUEST_TIMEOUT_FIELDNAME, requestTimeOut);
maxPoolSize = this.staticConf.getInteger(IBackend.MAXPOOL_SIZE_FIELDNAME, maxPoolSize);
minSessionPoolSize = this.staticConf.getInteger(IBackend.MIN_SESSION_POOL_SIZE_FIELDNAME, minSessionPoolSize);
keepAliveMaxRequest = this.staticConf.getLong(IBackend.KEEPALIVE_MAXREQUEST_FIELDNAME, keepAliveMaxRequest);
keepAliveTimeOut = this.staticConf.getLong(IBackend.KEEPALIVE_TIMEOUT_FIELDNAME, keepAliveTimeOut);
enableChunked = this.staticConf.getBoolean(ENABLE_CHUNCKED_FIELDNAME, enableChunked);
enableAccessLog = this.staticConf.getBoolean(ENABLE_ACCESSLOG_FIELDNAME, enableAccessLog);
return this;
}
/**
* Gets the bad backends map.
*
* @return the bad backends map
*/
public EntitiesMap<IBackend> getBadBackends() {
return badBackends;
}
/**
* Gets the length of bad backend pool.
*
* @return the length of bad backend pool
*/
public int getNumBadBackend() {
return badBackends.getNumEntities();
}
/**
* Gets the bad backend by id.
*
* @param entityId the entity id
* @return the bad backend by id
*/
public IBackend getBadBackendById(String entityId) {
return badBackends.getEntityById(entityId);
}
/**
* Clear bad backend.
*/
public void clearBadBackend() {
for (IBackend backend: badBackends.getEntities().values()) {
backend.closeAllForced();
}
badBackends.clearEntities();
}
/**
* Adds the bad backend.
*
* @param entity the entity
* @return true, if successful
*/
public boolean addBadBackend(IBackend entity) {
((Entity) entity).setStatus(StatusType.FAILED_STATUS);
entity.closeAllForced();
return badBackends.addEntity(entity);
}
/**
* Removes the bad backend.
*
* @param entity the entity
* @return true, if successful
*/
public boolean removeBadBackend(IBackend entity) {
return badBackends.removeEntity(entity);
}
/**
* Removes the bad backend by id.
*
* @param id the id
* @return true, if successful
*/
public boolean removeBadBackend(String id) {
return badBackends.removeEntity(id);
}
/**
* Removes the bad backend.
*
* @param json the json
* @return true, if successful
*/
public boolean removeBadBackend(JsonObject json) {
return badBackends.removeEntity(json);
}
/**
* Clear all.
*/
public void clearAll() {
clearEntities();
clearBadBackend();
}
/**
* Checks if is chunked.
*
* @return true, if chunked
*/
public Boolean isChunked() {
return enableChunked;
}
/**
* Checks if access log is enabled.
*
* @return true, if enabled
*/
public Boolean hasAccessLog() {
return enableAccessLog;
}
public String getHealthCheck() {
return getOrCreateProperty(HEALTHCHECK_FIELDNAME, "/").toString();
}
}