Skip to content
This repository has been archived by the owner on Jan 21, 2024. It is now read-only.

Commit

Permalink
Refactoring and improvement of the BSS Sample
Browse files Browse the repository at this point in the history
  • Loading branch information
Carlos Manias committed May 19, 2015
1 parent c101fb2 commit 21b7f64
Show file tree
Hide file tree
Showing 23 changed files with 1,085 additions and 264 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,15 @@
*/
package com.ibm.sbt.provisioning.sample.app;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import com.ibm.commons.util.io.json.JsonException;
import com.ibm.commons.util.io.json.JsonJavaArray;
import com.ibm.commons.util.io.json.JsonJavaObject;
import com.ibm.sbt.provisioning.sample.app.model.Rest;
import com.ibm.sbt.provisioning.sample.app.model.Weight;
import com.ibm.sbt.provisioning.sample.app.model.Weights;
import com.ibm.sbt.provisioning.sample.app.task.BSSProvisioning;
import com.ibm.sbt.provisioning.sample.app.util.BSSEndpoints;
import com.ibm.sbt.services.client.base.datahandlers.JsonDataHandler;
import com.ibm.sbt.provisioning.sample.app.util.ShutdownCommand;

/**
* This class represents a singleton responsible for managing the current weight associated with the organization .
Expand All @@ -38,6 +33,7 @@ public class WeightManager {
private static final Logger logger = Logger.getLogger(WeightManager.class.getName());

private static WeightManager instance = null;
private static ShutdownCommand command;
/**
* An int keeping track of the load generated by a customer towards the BSS API
* while provisioning its subscribers
Expand All @@ -56,50 +52,46 @@ public class WeightManager {
* An int representing the load threshold for a customer
* */
private long threshold ;
/**
* <code>Map</code> keeping track of the weight associated with each call to the BSS API
* */
private Map<String, Integer> weightPerBSSCall ;
/**
* <code>Map</code> keeping track of the number of times a BSS endpoint is hit using the same HTTP method
* */
private Map<String, Integer> counterPerBSSCall ;
/**
* <code>Executor</code> needed for periodically reset the {@link #currentWeight}
* */
private ScheduledExecutorService resetterExec ;

protected ScheduledExecutorService resetterExec;
/**
* <code>Executor</code> needed for periodically submit he {@link com.ibm.sbt.provisioning.sample.app.task.SubscriberTask}
* instances to the provisioning threadpool ( {@link com.ibm.sbt.provisioning.sample.app.task.BSSProvisioning#getThreadPool()} ) .
* */
private ScheduledExecutorService bssProvExec ;
protected ScheduledExecutorService bssProvExec;

public static synchronized WeightManager getInstance() {
if (instance == null)
instance = new WeightManager(BSSProvisioning.getWeightsFile());
if(instance == null) {
instance = new WeightManager(BSSProvisioning.getWeights());
}
return instance;
}

/**
* Allows to set an arbitrary command to be executed at shutdown time
* @param shutdownCommand
*/
public static void setCommand(ShutdownCommand shutdownCommand){
command = shutdownCommand;
}

/**
* Constructor responsible for the {@link #resetterExec} and {@link #bssProvExec} <code>Executor</code>(s)
* initialization, for the weights json input file parsing and loading of its content in the {@link #weightPerBSSCall}
* <code>Map</code>, and initialization of the {@link #resetDuration}, {@link #maxSystemWeight} and
* {@link #threshold} fields
* */
public WeightManager( String settingsFilePath ){
private WeightManager(Weights weights){
this.resetterExec = Executors.newSingleThreadScheduledExecutor();
this.bssProvExec = Executors.newSingleThreadScheduledExecutor();
this.threshold = weights.getLimit();

this.weightPerBSSCall = this.getweightPerBSSCall(settingsFilePath);
this.counterPerBSSCall = new HashMap<String, Integer>();
for( String key : this.weightPerBSSCall.keySet() ){
this.counterPerBSSCall.put( key , 0 ) ;
}
// number of seconds needed for scheduling the BSSProvisioning.getSubscribersTasks() queue +
// ( approximate time for the initial customer and subscription creation and activation + 30sec )
long firstBSSProvisioningIt = (((long)BSSProvisioning.getSubscribersQuantity())/4L)*1000L + 60000L ;
long firstBSSProvisioningIt = (((long)BSSProvisioning.getSubscribersQuantity().get())/4L)*1000L + 60000L ;
this.resetDuration = weights.getResetDuration();
this.resetterExec.scheduleAtFixedRate( new Resetter(), this.resetDuration , this.resetDuration, TimeUnit.MILLISECONDS );
this.bssProvExec.scheduleAtFixedRate( new BSSProvisioning(), firstBSSProvisioningIt , 30000L, TimeUnit.MILLISECONDS );

}

/**
Expand All @@ -119,6 +111,7 @@ public void run(){
WeightManager.this.resetCurrentWeight();
}
}

/**
* This <code>synchronized</code> method simply reset the {@link #currentWeight} and
* set the {@link #thresholdReached} value to <code>false</code>
Expand All @@ -129,126 +122,92 @@ private synchronized void resetCurrentWeight(){
}

/**
* This method will update the {@link #currentWeight} associated with the organization depending on the call being made.
* This method will update the {@link #currentWeight} associated with the organization depending
* on the call being made.
* <p>
* @param key a String identifying the call being made<br>
* @return <code>true</code> if the call is permitted because the {@link #threshold} has not been reached after the {@link #currentWeight} update ,
* <code>false</code> otherwise
*
* @param key a String identifying the call being made<br>
* @return <code>true</code> if the call is permitted because the {@link #threshold} has not been
* reached after the {@link #currentWeight} update , <code>false</code> otherwise
*/
public synchronized boolean updateCurrentWeight( String key ){
public synchronized boolean updateCurrentWeight(String url, Rest method){
boolean callPermitted = true ;
if( !thresholdReached ){
logger.finest("currentWeight = " + this.currentWeight);
this.currentWeight = this.currentWeight + weightPerBSSCall.get(key) ;
this.currentWeight = this.currentWeight + getWeightValuePerBSSCall(url, method);
logger.finest("currentWeight updated = " + this.currentWeight);
if( currentWeight >= threshold ){
callPermitted = false ;
logger.warning("THRESHOLD REACHED OR EXCEEDED !!!");
this.thresholdReached = true ;
}else{
this.counterPerBSSCall.put( key , this.counterPerBSSCall.get(key) + 1 ) ;
this.incrementCounterPerBSSCall(url, method, 1);
}
}else{
callPermitted = false ;
}
return callPermitted ;
}

/**
* {@link #resetDuration} getter method
*/
public long getResetDuration() {
return resetDuration;
}

/**
* {@link #maxSystemWeight} getter method
*/
public long getMaxSystemWeight() {
return maxSystemWeight;
}

/**
* {@link #threshold} getter method
*/
public long getThreshold() {
return threshold;
}

/**
* {@link #thresholdReached} getter method
*/
public synchronized boolean isThresholdReached() {
return thresholdReached;
}

public void shutdown(){
this.resetterExec.shutdownNow();
this.bssProvExec.shutdownNow();
BSSProvisioning.getThreadPool().shutdown();
}

/**
* This method is responsible for parsing the application input file
* specifying the weight of each call to the BSS API .
* <p>
* @param weightsFilePath weights json file path<br>
* @return a <code>Map</code> keeping track of the weight associated with each call to the BSS API
* Shuts down the ExecutorServices
*/
private Map<String, Integer> getweightPerBSSCall( String weightsFilePath ){
String weightsJson = null ;
Map<String, Integer> weightPerBSSCall = null ;
JsonDataHandler handler = null ;
try{
weightsJson = com.ibm.sbt.provisioning.sample.app.util.Util.readWeightsJson(weightsFilePath,BSSProvisioning.isWeightsFileAsInput());
handler = new JsonDataHandler(weightsJson);
}catch( IOException ioe ){
System.out.println(ioe.getMessage());
}catch (JsonException e) {
System.out.println(e.getMessage());
public void shutdown(){
if(!this.resetterExec.isShutdown()){
this.resetterExec.shutdownNow();
}
if( weightsJson != null && handler != null ) {
weightPerBSSCall = new HashMap<String, Integer>();
long resetDuration = handler.getAsLong("settings/resetDuration");
long maxSystemWeight = handler.getAsLong("settings/maxSystemWeight");
long threshold = handler.getAsLong("default/limit");
this.maxSystemWeight = maxSystemWeight ;
this.resetDuration = resetDuration ;
this.threshold = threshold ;

JsonJavaObject defaultObj = (JsonJavaObject)handler.getAsObject("default");
for( BSSEndpoints endpoint : BSSEndpoints.values() ){
if(endpoint.getEndpointString().equals("/") ||
endpoint.getEndpointString().equals("/service/authentication") ||
endpoint.getEndpointString().equals("/service/authentication/changepassword") ||
endpoint.getEndpointString().equals("/service/authentication/getrolelist") ){
JsonJavaArray jsonArray = defaultObj.getAsArray(endpoint.getEndpointString());
JsonJavaObject weightArr = (JsonJavaObject)jsonArray.get(0);
String callWeight = weightArr.getString("weight");
weightPerBSSCall.put(endpoint.getEndpointString(), Integer.parseInt(callWeight.replace(".0", "")) );
}else{
JsonJavaArray resourceCustomer = defaultObj.getAsArray(endpoint.getEndpointString());
for( int i = 0 ; i < resourceCustomer.length() ; i++){
JsonJavaObject entry = (JsonJavaObject)resourceCustomer.get(i);
String callWeight = entry.getString("weight");
String method = entry.getString("method");
weightPerBSSCall.put(endpoint.getEndpointString()+":" + method, Integer.parseInt(callWeight.replace(".0", "")) );
}
}
}
logger.finest("latest weights settings :");
for(String key : weightPerBSSCall.keySet()){
logger.finest(key+"="+weightPerBSSCall.get(key));
}
if(!this.bssProvExec.isShutdown()){
this.bssProvExec.shutdownNow();
}
if(!BSSProvisioning.getThreadPool().isShutdown()){
BSSProvisioning.getThreadPool().shutdown();
}
if(command != null){
command.execute();
}
return weightPerBSSCall ;
}

/**
* {@link #weightPerBSSCall} getter method
*/
public Map<String, Integer> getWeightPerBSSCall() {
return weightPerBSSCall;
public Weight getWeightPerBSSCall(String url, Rest method){
return BSSProvisioning.getWeights().getWeight(url, method);
}
/**
* {@link #counterPerBSSCall} getter method
*/
public Map<String, Integer> getCounterPerBSSCall() {
return counterPerBSSCall;

public int getWeightValuePerBSSCall(String url, Rest method){
return BSSProvisioning.getWeights().getWeightValue(url, method);
}

public int incrementCounterPerBSSCall(String url, Rest method, int amount){
return BSSProvisioning.getWeights().incrementCounter(url, method, amount);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class CustomFilter implements Filter{
@Override
public boolean isLoggable(LogRecord record) {
boolean isLoggable = true ;
if(record.getLoggerName().startsWith("org.apache") ||
if(record.getLoggerName() == null || record.getLoggerName().startsWith("org.apache") ||
record.getLoggerName().startsWith("com.ibm.sbt.service.proxy.SBTProxy") ||
record.getLoggerName().startsWith("com.ibm.sbt.services.client.ClientService") ){
isLoggable = false ;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* © Copyright IBM Corp. 2014
*
* 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.ibm.sbt.provisioning.sample.app.model;

/**
* Just a simple enum to work with REST Operations
*
* @author Carlos Manias
*
*/
public enum Rest{
GET, POST, PUT, DELETE, ALL
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* © Copyright IBM Corp. 2015
*
* 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.ibm.sbt.provisioning.sample.app.model;

/**
* This class models a subscription and its entitlement state for a subscriber
*
* @author Carlos Manias
*
*/
public class SubscriptionEntitlement{
private String partNumber;
private String subscriptionId;
private NotesType notesType;

public static enum NotesType{
NONE(""), NOTES("dom__emailAddress"), INOTES("yun__emailAddress");
private String attribute;

NotesType(String attribute){
this.attribute = attribute;
}

public String getAttribute(){
return attribute;
}
};

public SubscriptionEntitlement(String partNumber, String subscriptionId, NotesType notesType){
this.partNumber = partNumber;
this.subscriptionId = subscriptionId;
this.notesType = notesType;
}

public String getPartNumber(){
return this.partNumber;
}

public String getSubscriptionId(){
return this.subscriptionId;
}

public NotesType getNotesType(){
return this.notesType;
}
}
Loading

0 comments on commit 21b7f64

Please sign in to comment.