Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2019, Continual.io
*
* 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 io.continual.services;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.continual.builder.Builder;
import io.continual.builder.Builder.BuildFailure;
import io.continual.builder.sources.BuilderJsonDataSource;
import io.continual.util.collections.MultiMap;
import io.continual.util.console.ConsoleProgram.StartupFailureException;
import io.continual.util.data.exprEval.EnvDataSource;
import io.continual.util.data.exprEval.ExprDataSourceStack;
import io.continual.util.data.exprEval.ExpressionEvaluator;
import io.continual.util.data.exprEval.JsonDataSource;
import io.continual.util.data.exprEval.SpecialFnsDataSource;
import io.continual.util.nv.NvReadable;
public class ServiceContainer
{
public static final String kServices = "services";
public static final String kServicesChar = "s";
public static final String kProfile = "profile";
public static final String kProfileChar = "p";
public static ServiceContainer build ( NvReadable p, boolean withStart ) throws StartupFailureException
{
return build ( p, withStart, new Server.StdFactory () );
}
public static T build ( NvReadable p, boolean withStart, ServiceContainerFactory scf ) throws StartupFailureException
{
final String services = p.getString ( kServices, "services.json" );
if ( services == null )
{
throw new StartupFailureException ( "No services configuration name provided." );
}
final InputStream serviceStream = ServiceContainer.class.getClassLoader ().getResourceAsStream ( services );
if ( serviceStream == null )
{
throw new StartupFailureException ( "No service stream available." );
}
return build ( serviceStream, p.getStrings ( kProfile, new String[]{"default"} ), withStart, scf );
}
public static ServiceContainer build ( InputStream serviceStream, String[] profiles, boolean withStart ) throws StartupFailureException
{
return build ( serviceStream, profiles, withStart, new Server.StdFactory () );
}
public static T build ( InputStream serviceStream, String[] profiles, boolean withStart, ServiceContainerFactory scf ) throws StartupFailureException
{
final T svcContainer = scf.create ();
if ( serviceStream == null )
{
throw new StartupFailureException ( "No stream provided" );
}
// read the config
final ServiceSet tlc = ServiceSet.readConfig ( new InputStreamReader ( serviceStream ) );
// apply any profiles
for ( String profile : profiles )
{
log.info ( "Profile [" + profile + "] is active." );
tlc.applyProfile ( profile );
}
// load the services
for ( ServiceConfig sc : tlc.getServices () )
{
if ( sc.enabled () )
{
log.info ( "Service [" + sc.getName() + "] is enabled..." );
try
{
final Service s = Builder.withBaseClass ( Service.class )
.usingClassName ( sc.getClassname () )
.usingData ( new BuilderJsonDataSource ( sc.toJson() ) )
.providingContext ( svcContainer )
.build ();
svcContainer.add ( sc.getName (), s );
}
catch ( BuildFailure e )
{
throw new StartupFailureException ( e );
}
}
else
{
log.info ( "Service [" + sc.getName() + "] is disabled." );
}
}
try
{
if ( withStart )
{
// startup the services
log.info ( "Starting services..." );
svcContainer.startAll ();
log.info ( "Server is ready." );
}
}
catch ( Service.FailedToStart e )
{
throw new StartupFailureException ( e );
}
return svcContainer;
}
public ServiceContainer ()
{
fServices = new LinkedList ();
fServiceByName = new MultiMap ();
}
public synchronized ServiceContainer add ( String name, Service s )
{
fServices.add ( s );
if ( name != null )
{
final int count = fServiceByName.size ( name );
if ( count > 0 )
{
log.warn ( "While adding service [{}], {} instances are already present.", name, count );
}
fServiceByName.put ( name, s );
}
return this;
}
public synchronized List getServiceNames ()
{
return new LinkedList ( fServiceByName.getKeys () );
}
public synchronized List getServices ()
{
return new LinkedList ( fServices );
}
@SuppressWarnings("unchecked")
public synchronized T get ( String name, Class asClass )
{
if ( name == null ) return null;
final List svcs = fServiceByName.get ( name );
if ( svcs != null )
{
for ( Service svc : svcs )
{
if ( asClass.isInstance ( svc ) )
{
return (T) svc;
}
}
}
return null;
}
/**
* Get a service by class.
* @param
* @param asClass
* @return an instance of the target class or null
*/
@SuppressWarnings("unchecked")
public synchronized T get ( Class asClass )
{
for ( Service svc : fServices )
{
if ( asClass.isInstance ( svc ) )
{
return (T) svc;
}
}
return null;
}
/**
* Get a required service by class.
* @param
* @param asClass
* @return an instance of the target class or null
* @throws BuildFailure
*/
public synchronized T getReqd ( Class asClass ) throws BuildFailure
{
T result = get ( asClass );
if ( result == null )
{
throw new BuildFailure ( "Couldn't locate a " + asClass.getName () );
}
return result;
}
/**
* Get a named service, throwing BuildFailure if it's not found.
* @param the target class
* @param name the service name
* @param asClass the target class
* @return an instance of the target class
* @throws BuildFailure
*/
public synchronized T getReqd ( String name, Class asClass ) throws BuildFailure
{
T result = get ( name, asClass );
if ( result == null )
{
throw new BuildFailure ( "Couldn't locate a " + asClass.getName () + " named " + name );
}
return result;
}
/**
* Get a named service, throwing BuildFailure if it's not found and name is not null.
* @param the target class
* @param name the service name
* @param asClass the target class
* @return an instance of the target class
* @throws BuildFailure
*/
public synchronized T getReqdIfNotNull ( String name, Class asClass ) throws BuildFailure
{
if ( name == null ) return null;
T result = get ( name, asClass );
if ( result == null )
{
throw new BuildFailure ( "Couldn't locate a " + asClass.getName () + " named " + name );
}
return result;
}
public void startAll () throws Service.FailedToStart
{
try
{
// startup the services
for ( Entry> svcEntry : fServiceByName.getValues().entrySet() )
{
log.info ( "Starting service [{}]...", svcEntry.getKey () );
for ( Service svc : svcEntry.getValue() )
{
svc.start ();
}
}
}
catch ( Service.FailedToStart e )
{
stopAll ();
throw e;
}
}
public void stopAll ()
{
// stop the services
for ( Service svc : getServices () )
{
svc.requestFinish ();
}
}
public void awaitTermination () throws InterruptedException
{
int runCount = Integer.MAX_VALUE;
while ( runCount > 0 )
{
// service implementation is wide-open, so there's not a good way
// to enforce a signal to wait on. Here, we just poll.
Thread.sleep ( 250 );
runCount = 0;
for ( Service s : getServices () )
{
if ( s.isRunning () ) runCount++;
}
}
}
public ExpressionEvaluator getExprEval ()
{
return getExprEval ( null );
}
public ExpressionEvaluator getExprEval ( JSONObject data )
{
final ExprDataSourceStack stack = new ExprDataSourceStack (
new JsonDataSource ( data ),
new EnvDataSource (),
new SpecialFnsDataSource ()
);
return new ExpressionEvaluator ( stack );
}
private final LinkedList fServices;
private final MultiMap fServiceByName;
private static final Logger log = LoggerFactory.getLogger ( ServiceContainer.class );
}