
io.continual.http.service.framework.routing.playish.CHttpPlayishInstanceCallRoutingSource Maven / Gradle / Ivy
/*
* 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.http.service.framework.routing.playish;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import org.slf4j.LoggerFactory;
import io.continual.http.service.framework.context.CHttpRequestContext;
import io.continual.http.service.framework.routing.CHttpRouteInvocation;
import io.continual.http.service.framework.routing.CHttpRouteSource;
import io.continual.util.naming.Path;
/**
* This routing source routes to methods on an object instance.
*/
public class CHttpPlayishInstanceCallRoutingSource implements CHttpRouteSource
{
public CHttpPlayishInstanceCallRoutingSource ( T instance, URL url ) throws IOException
{
fInstance = instance;
fPathList = new LinkedList ();
fPackages = new LinkedList ();
if ( url == null )
{
throw new IOException ( "URL for routing file is null in CHttpPlayishInstanceCallRoutingSource ( URL u )" );
}
loadRoutes ( url );
}
public CHttpPlayishInstanceCallRoutingSource ( T instance, InputStream is ) throws IOException
{
fInstance = instance;
fPathList = new LinkedList ();
fPackages = new LinkedList ();
loadRoutes ( is );
}
/**
* Add a verb and path route with an action string. The action can start with "staticDir:" or
* "staticFile:". The remainder of the string is used as a relative filename to the dir (staticDir:), or
* as a filename (staticFile:).
* @param verb
* @param path
* @param action
* @return this object (for use in chaining the add calls)
*/
public synchronized CHttpPlayishInstanceCallRoutingSource addRoute ( String verb, String path, String action )
{
final CHttpPathInfo pe = CHttpPathInfo.processPath ( verb, path );
pe.setHandler ( new InstanceEntryAction ( fInstance, action, pe.getArgs(), fPackages ) );
fPathList.add ( pe );
return this;
}
/**
* Get a route invocation for a given verb+path, or null.
*/
@Override
public synchronized CHttpRouteInvocation getRouteFor ( String verb, String path )
{
CHttpRouteInvocation selected = null;
for ( CHttpPathInfo pe : fPathList )
{
final List args = pe.matches ( verb, path );
if ( args != null )
{
selected = getInvocation ( pe, args );
break;
}
}
return selected;
}
/**
* Get the URL that reaches a given static method with the given arguments.
*/
@Override
public String getRouteTo ( Class> c, String staticMethodName, Map args )
{
final String fullname = c.getName() + "." + staticMethodName;
for ( CHttpPathInfo pe : fPathList )
{
if ( pe.invokes ( fullname ) )
{
return pe.makePath ( args );
}
}
return null;
}
private final T fInstance;
private final LinkedList fPackages;
private final LinkedList fPathList;
private static final org.slf4j.Logger log = LoggerFactory.getLogger ( CHttpPlayishInstanceCallRoutingSource.class );
protected Invocation getInvocation ( CHttpPathInfo pe, List args )
{
return new Invocation ( pe, args );
}
protected class Invocation implements CHttpRouteInvocation
{
public Invocation ( CHttpPathInfo pe, List args )
{
fPe = pe;
fArgs = args;
}
@Override
public void run ( CHttpRequestContext ctx ) throws IOException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
{
fPe.getHandler ().handle ( ctx, fArgs );
}
@Override
public Path getRouteNameForMetrics ()
{
String pathPart = fPe.getPath();
if ( !pathPart.startsWith ( Path.getPathSeparatorString () ) )
{
pathPart = Path.getPathSeparatorString () + pathPart;
}
if ( pathPart.equals ( Path.getPathSeparatorString () ) )
{
pathPart = "(root)";
}
else if ( pathPart.endsWith ( Path.getPathSeparatorString () ) )
{
pathPart = pathPart.substring ( 0, pathPart.length () - 1 );
}
return Path.fromString ( Path.getPathSeparatorString () + fPe.getVerb () + pathPart );
}
private final CHttpPathInfo fPe;
private final List fArgs;
}
protected synchronized void clearRoutes ()
{
log.debug ( "Clearing routes within this instance route source." );
fPathList.clear ();
}
protected synchronized void addPackage ( String pkg )
{
fPackages.add ( pkg );
}
private synchronized void loadRoutes ( URL u ) throws IOException
{
loadRoutes ( new InputStreamReader ( u.openStream () ) );
}
private synchronized void loadRoutes ( InputStream is ) throws IOException
{
loadRoutes ( new InputStreamReader ( is ) );
}
private synchronized void loadRoutes ( Reader r ) throws IOException
{
clearRoutes ();
final BufferedReader fr = new BufferedReader ( r );
String line;
while ( ( line = fr.readLine () ) != null )
{
line = line.trim ();
if ( line.length () > 0 && !line.startsWith ( "#" ) )
{
processLine ( line );
}
}
}
private void processLine ( String line )
{
try
{
final StringTokenizer st = new StringTokenizer ( line );
final String verb = st.nextToken ();
if ( verb.toLowerCase ().equals ( "package" ) )
{
final String pkg = st.nextToken ();
addPackage ( pkg );
}
else
{
final String path = st.nextToken ();
final String action = st.nextToken ();
addRoute ( verb, path, action );
}
}
catch ( NoSuchElementException e )
{
log.warn ( "There was an error processing route config line: \"" + line + "\"" );
}
catch ( IllegalArgumentException e )
{
log.warn ( "There was an error processing route config line: \"" + line + "\": " + e.getMessage () );
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy