├── .gitattributes ├── .gitignore ├── README.md ├── boson ├── README.md ├── polo-serialization.png ├── pom.xml └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── higgs │ │ │ └── boson │ │ │ ├── BosonMessage.java │ │ │ ├── BosonType.java │ │ │ ├── IllegalBosonResponseType.java │ │ │ └── serialization │ │ │ ├── BosonProperty.java │ │ │ ├── InvalidDataException.java │ │ │ ├── InvalidRequestResponseTypeException.java │ │ │ ├── UnsupportedBosonTypeException.java │ │ │ ├── mutators │ │ │ ├── ClassMutator.java │ │ │ ├── MutatorFactory.java │ │ │ ├── ReadMutator.java │ │ │ ├── ReadWriteMutator.java │ │ │ └── WriteMutator.java │ │ │ └── v1 │ │ │ ├── BosonReader.java │ │ │ └── BosonWriter.java │ └── resources │ │ └── log4j.properties │ └── test │ └── java │ └── io │ └── higgs │ └── boson │ └── serialization │ └── v1 │ ├── BosonWriterTest.java │ ├── CircularReferenceA.java │ └── CircularReferenceB.java ├── checkstyle.xml ├── core ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── higgs │ │ └── core │ │ ├── ConfigUtil.java │ │ ├── EventListenerMethod.java │ │ ├── FileUtil.java │ │ ├── FixedSortedList.java │ │ ├── HiggsInterceptor.java │ │ ├── HiggsServer.java │ │ ├── InvokableMethod.java │ │ ├── MessageHandler.java │ │ ├── MethodProcessor.java │ │ ├── ObjectFactory.java │ │ ├── ParameterExtractor.java │ │ ├── ProtocolConfiguration.java │ │ ├── ProtocolDetector.java │ │ ├── ProtocolDetectorFactory.java │ │ ├── ResolvedFile.java │ │ ├── ResourceNotFoundException.java │ │ ├── ResourcePath.java │ │ ├── ServerConfig.java │ │ ├── Sortable.java │ │ ├── StaticUtil.java │ │ ├── Transducer.java │ │ ├── func │ │ ├── Function.java │ │ ├── Function1.java │ │ └── Function2.java │ │ ├── reflect │ │ ├── ReflectionUtil.java │ │ ├── classpath │ │ │ ├── CachedPath.java │ │ │ ├── HiggsClassLoader.java │ │ │ ├── HiggsClassPathCache.java │ │ │ └── PackageScanner.java │ │ └── dependency │ │ │ ├── DependencyProvider.java │ │ │ └── Injector.java │ │ └── ssl │ │ ├── SSLConfigFactory.java │ │ ├── SSLConfiguration.java │ │ └── SSLContextFactory.java │ └── resources │ └── log4j.properties ├── events ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── higgs │ │ └── events │ │ ├── Event.java │ │ ├── EventHandler.java │ │ ├── EventMessage.java │ │ ├── EventMethod.java │ │ ├── EventMethodProcessor.java │ │ ├── EventServer.java │ │ ├── Events.java │ │ ├── FunctionEventMethod.java │ │ ├── SingletonFactory.java │ │ ├── Task.java │ │ ├── TypeMismatch.java │ │ └── demo │ │ ├── ClassExample.java │ │ ├── Demo.java │ │ └── RandomObject.java │ └── resources │ └── log4j.properties ├── examples ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── higgs │ │ └── examples │ │ ├── boson │ │ ├── DemoClient.java │ │ ├── Nested.java │ │ ├── NestedField.java │ │ └── PoloExample.java │ │ ├── httpClient │ │ └── Demo.java │ │ ├── httpServer │ │ └── restService │ │ │ ├── Api.java │ │ │ └── Demo.java │ │ ├── websocketClient │ │ └── WebSocketDemo.java │ │ └── websocketServer │ │ ├── Api.java │ │ ├── Pojo.java │ │ └── WebSocketDemo.java │ └── resources │ └── log4j.properties ├── http ├── README.md ├── client │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── io │ │ │ │ └── higgs │ │ │ │ └── http │ │ │ │ └── client │ │ │ │ ├── ClientHandler.java │ │ │ │ ├── ClientIntializer.java │ │ │ │ ├── ConnectHandler.java │ │ │ │ ├── FutureResponse.java │ │ │ │ ├── HTTPStreamingRequest.java │ │ │ │ ├── HttpFile.java │ │ │ │ ├── HttpRequestBuilder.java │ │ │ │ ├── JSONRequest.java │ │ │ │ ├── POST.java │ │ │ │ ├── ProxyConnectionException.java │ │ │ │ ├── ProxyDemo.java │ │ │ │ ├── Request.java │ │ │ │ ├── RequestTimeoutException.java │ │ │ │ ├── Response.java │ │ │ │ ├── RetryPolicy.java │ │ │ │ └── readers │ │ │ │ ├── FileReader.java │ │ │ │ ├── JsonStreamReader.java │ │ │ │ ├── LineReader.java │ │ │ │ ├── PageReader.java │ │ │ │ └── Reader.java │ │ └── resources │ │ │ ├── log4j.properties │ │ │ └── logging.properties │ │ └── test │ │ └── java │ │ └── io │ │ └── higgs │ │ └── http │ │ └── client │ │ └── JSONRequestTest.java ├── pom.xml └── server │ ├── README.md │ ├── pom.xml │ ├── s3 │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── io │ │ │ └── higgs │ │ │ └── http │ │ │ └── server │ │ │ ├── DefaultParamInjector.java │ │ │ ├── HttpRequest.java │ │ │ ├── HttpRequestDecoder.java │ │ │ ├── HttpResponse.java │ │ │ ├── HttpResponseEncoder.java │ │ │ ├── HttpStatus.java │ │ │ ├── HttpTemplate.java │ │ │ ├── ManagedWriter.java │ │ │ ├── MessagePusher.java │ │ │ ├── MethodParam.java │ │ │ ├── ParamInjector.java │ │ │ ├── StaticFileMethod.java │ │ │ ├── Transcriber.java │ │ │ ├── Transcription.java │ │ │ ├── WrappedResponse.java │ │ │ ├── auth │ │ │ ├── DefaultHiggsSessionDAO.java │ │ │ ├── FlashValue.java │ │ │ ├── HiggsSecurityManager.java │ │ │ ├── HiggsSession.java │ │ │ ├── HiggsSessionFactory.java │ │ │ ├── HiggsSessionManager.java │ │ │ └── InvalidSessionDirectory.java │ │ │ ├── config │ │ │ └── HttpConfig.java │ │ │ ├── errors │ │ │ └── HttpError.java │ │ │ ├── jaxrs │ │ │ ├── JaxRsResponse.java │ │ │ ├── ResponseBuilder.java │ │ │ └── SimpleRuntimeDelegate.java │ │ │ ├── params │ │ │ ├── DefaultValidator.java │ │ │ ├── FormFiles.java │ │ │ ├── FormParams.java │ │ │ ├── HttpCookie.java │ │ │ ├── HttpCookies.java │ │ │ ├── HttpFile.java │ │ │ ├── IllegalValidatorException.java │ │ │ ├── QueryParams.java │ │ │ ├── RequiredParam.java │ │ │ ├── SessionParam.java │ │ │ ├── ValidationResult.java │ │ │ ├── Validator.java │ │ │ └── valid.java │ │ │ ├── protocol │ │ │ ├── HttpDetector.java │ │ │ ├── HttpDetectorFactory.java │ │ │ ├── HttpHandler.java │ │ │ ├── HttpMethod.java │ │ │ ├── HttpMethodProcessor.java │ │ │ ├── HttpProtocolConfiguration.java │ │ │ ├── MediaTypeDecoder.java │ │ │ └── mediaTypeDecoders │ │ │ │ ├── FormUrlEncodedDecoder.java │ │ │ │ └── JsonDecoder.java │ │ │ ├── resource │ │ │ ├── JsonData.java │ │ │ ├── MediaType.java │ │ │ └── template.java │ │ │ └── transformers │ │ │ ├── BaseTransformer.java │ │ │ └── ResponseTransformer.java │ │ └── resources │ │ ├── config.yml │ │ ├── log4j.properties │ │ ├── public │ │ ├── default.html │ │ ├── demo.html │ │ ├── favicon.ico │ │ ├── header.html │ │ ├── index.html │ │ └── sub │ │ │ ├── defaultt.html │ │ │ └── random.html │ │ ├── shiro.ini │ │ └── templates │ │ ├── api.html │ │ ├── api_en.properties │ │ ├── api_es.properties │ │ ├── api_fr.properties │ │ ├── error │ │ └── default.html │ │ ├── footer.html │ │ ├── header.html │ │ └── index.moustache │ ├── transformer-defaults │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── io │ │ │ └── higgs │ │ │ └── http │ │ │ └── server │ │ │ └── transformers │ │ │ ├── ChunkedFileWriter.java │ │ │ ├── JsonResponseError.java │ │ │ ├── JsonTransformer.java │ │ │ ├── StaticFileTransformer.java │ │ │ ├── StaticFileWriter.java │ │ │ └── conf │ │ │ ├── FilesConfig.java │ │ │ └── JsonConfig.java │ │ └── resources │ │ ├── json_config.yml │ │ ├── public │ │ └── index.html │ │ ├── static_file_config.yml │ │ └── templates │ │ ├── error │ │ └── default.html │ │ └── index.moustache │ ├── transformer-handlebars │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── io │ │ │ └── higgs │ │ │ └── http │ │ │ └── server │ │ │ ├── config │ │ │ └── HandlebarsConfig.java │ │ │ └── transformers │ │ │ └── handlebars │ │ │ ├── HandlebarHelper.java │ │ │ ├── HandlebarsTransformer.java │ │ │ ├── HiggsTemplateLoader.java │ │ │ └── HiggsTemplateSource.java │ │ └── resources │ │ ├── handlebars_config.yml │ │ └── templates │ │ └── error │ │ └── default.hbs │ ├── transformer-mustache │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── io │ │ │ └── higgs │ │ │ └── http │ │ │ └── server │ │ │ ├── config │ │ │ └── MustacheConfig.java │ │ │ └── transformers │ │ │ └── mustache │ │ │ ├── HiggsMustacheFactory.java │ │ │ └── MustacheTransformer.java │ │ └── resources │ │ ├── mustache_config.yml │ │ ├── public │ │ └── index.html │ │ └── templates │ │ ├── error │ │ └── default.html │ │ └── index.mustache │ └── transformer-thymeleaf │ ├── README.md │ ├── pom.xml │ └── src │ └── main │ ├── java │ └── io │ │ └── higgs │ │ └── http │ │ └── server │ │ ├── config │ │ └── TemplateConfig.java │ │ └── transformers │ │ ├── ThymeleafTransformer.java │ │ └── thymeleaf │ │ ├── Thymeleaf.java │ │ └── WebContext.java │ └── resources │ ├── log4j.properties │ ├── public │ ├── default.html │ ├── demo.html │ ├── favicon.ico │ ├── header.html │ ├── index.html │ └── sub │ │ ├── defaultt.html │ │ └── random.html │ ├── templates │ ├── api.html │ ├── api_en.properties │ ├── api_es.properties │ ├── api_fr.properties │ ├── error │ │ └── default.html │ ├── footer.html │ ├── header.html │ └── index.moustache │ └── thymeleaf_config.yml ├── pom.xml └── websocket ├── README.md ├── client ├── pom.xml └── src │ └── main │ └── java │ └── io │ └── higgs │ └── ws │ └── client │ ├── WebSocketClient.java │ ├── WebSocketClientHandler.java │ ├── WebSocketEventListener.java │ ├── WebSocketInitializer.java │ ├── WebSocketMessage.java │ ├── WebSocketServerEventListener.java │ └── WebSocketStream.java ├── pom.xml └── server ├── README.md ├── pom.xml └── src └── main ├── java └── io │ └── higgs │ └── ws │ ├── DefaultWebSocketEventHandler.java │ ├── JsonRequest.java │ ├── WebSocketEventHandler.java │ ├── protocol │ ├── WebSocketConfiguration.java │ ├── WebSocketDetector.java │ ├── WebSocketDetectorFactory.java │ └── WebSocketHandler.java │ └── sockjs │ └── SockJSProtocol.java └── resources ├── config.yml ├── flash-policy.xml ├── log4j.properties ├── public ├── default.html ├── favicon.ico ├── index.html └── sub │ ├── defaultt.html │ └── random.html └── templates ├── api.html ├── api_en.properties ├── api_es.properties ├── api_fr.properties ├── error └── default.html └── index.html /.gitattributes: -------------------------------------------------------------------------------- 1 | #for LF even on windows 2 | text eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # use glob syntax. 2 | syntax: glob 3 | *.ser 4 | *.class 5 | 6 | # idea 7 | .idea 8 | *.iml 9 | 10 | # building 11 | target 12 | build 13 | build.log 14 | log/* 15 | **/var/* 16 | -------------------------------------------------------------------------------- /boson/polo-serialization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zcourts/higgs/504504331ded8f276fc7862986747fdeff132d90/boson/polo-serialization.png -------------------------------------------------------------------------------- /boson/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | boson 4 | 0.0.25-SNAPSHOT 5 | ${project.artifactId} 6 | jar 7 | Higgs' Boson protocol implementation 8 | 9 | 10 | io.higgs 11 | higgs 12 | 0.0.25-SNAPSHOT 13 | ../pom.xml 14 | 15 | 16 | 17 | io.higgs 18 | core 19 | 0.0.25-SNAPSHOT 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/BosonMessage.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class BosonMessage { 7 | public Object[] arguments; 8 | public String method; 9 | public String callback; 10 | public short protocolVersion = 0x1; 11 | 12 | public BosonMessage(Object[] arguments, String method, String callback, short protocolVersion) { 13 | this.arguments = arguments; 14 | this.method = method; 15 | this.callback = callback; 16 | this.protocolVersion = protocolVersion; 17 | } 18 | 19 | public BosonMessage() { 20 | } 21 | 22 | public BosonMessage(Object[] arguments, String method, String callback) { 23 | this.arguments = arguments; 24 | this.method = method; 25 | this.callback = callback; 26 | } 27 | 28 | public BosonMessage(Object[] arguments, String method) { 29 | this.arguments = arguments; 30 | this.method = method; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/BosonType.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class BosonType { 7 | public static final int BYTE = 1; 8 | public static final int SHORT = 2; 9 | public static final int INT = 3; 10 | public static final int LONG = 4; 11 | public static final int FLOAT = 5; 12 | public static final int DOUBLE = 6; 13 | public static final int BOOLEAN = 7; 14 | public static final int CHAR = 8; 15 | public static final int NULL = 9; 16 | public static final int STRING = 10; 17 | public static final int ARRAY = 11; 18 | public static final int LIST = 12; 19 | public static final int MAP = 13; 20 | public static final int POLO = 14; 21 | public static final int REFERENCE = 15; 22 | public static final int SET = 16; 23 | public static final int ENUM = 17; 24 | //request response flags 25 | public static final int REQUEST_METHOD_NAME = -127; 26 | public static final int REQUEST_PARAMETERS = -126; 27 | public static final int REQUEST_CALLBACK = -125; 28 | public static final int RESPONSE_METHOD_NAME = -124; 29 | public static final int RESPONSE_PARAMETERS = -123; 30 | 31 | protected BosonType() { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/IllegalBosonResponseType.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson; 2 | 3 | public class IllegalBosonResponseType extends RuntimeException { 4 | /** 5 | * When a server responds with an object, if the client expects a different type 6 | * this field will be an instance of the object returned. The client can determine 7 | * what to do with it. 8 | */ 9 | public final Object param; 10 | 11 | public IllegalBosonResponseType(Object param, Throwable cause) { 12 | super("Invalid response", cause); 13 | this.param = param; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/serialization/BosonProperty.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Explicitly register an object's field to be serialized or ignored 10 | * 11 | * @author Courtney Robinson 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD }) 15 | public @interface BosonProperty { 16 | /** 17 | * Optionally provide a name for this field. 18 | * If no name is provided, by default the variable name is used 19 | * 20 | * @return 21 | */ 22 | String value() default ""; 23 | 24 | /** 25 | * Mark this field ignored, doing this causes the field not to be serialized 26 | * 27 | * @return 28 | */ 29 | boolean ignore() default false; 30 | 31 | boolean ignoreInheritedFields() default false; 32 | } 33 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/serialization/InvalidDataException.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class InvalidDataException extends RuntimeException { 7 | 8 | public InvalidDataException(String msg, Throwable c) { 9 | super(msg, c); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/serialization/InvalidRequestResponseTypeException.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class InvalidRequestResponseTypeException extends RuntimeException { 7 | public InvalidRequestResponseTypeException(String msg, Throwable c) { 8 | super(msg, c); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/serialization/UnsupportedBosonTypeException.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class UnsupportedBosonTypeException extends RuntimeException { 7 | public UnsupportedBosonTypeException(String msg, Throwable cause) { 8 | super(msg, cause); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/serialization/mutators/ClassMutator.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization.mutators; 2 | 3 | /** 4 | * Class mutators does what it says on the tin. It allows boson reader to set class properties 5 | * without reflection. 6 | * 7 | * @author Courtney Robinson 8 | */ 9 | public interface ClassMutator { 10 | } 11 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/serialization/mutators/MutatorFactory.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization.mutators; 2 | 3 | /** 4 | * Responsible for pooled mutators and creates new unpooled ones 5 | * 6 | * @author Courtney Robinson 7 | */ 8 | public class MutatorFactory { 9 | } 10 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/serialization/mutators/ReadMutator.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization.mutators; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * A write mutator provides an interface for setting fields on objects without reflection 7 | * 8 | * @author Courtney Robinson 9 | */ 10 | public interface ReadMutator extends ClassMutator { 11 | /** 12 | * @param klass the class to check 13 | * @param obj the instance of the class to check 14 | * @return true if this mutator can read fields from the given class or object either or both can be used 15 | * to determine true or false 16 | */ 17 | boolean canReadFields(Class klass, Object obj); 18 | 19 | /** 20 | * Gets the value of the given field from the provided instance 21 | * Preferably without using the Class object 22 | * 23 | * @param instance the instance to get the value from 24 | * @param klass the class of the instance 25 | * @param field the field to get @return The value of the given field 26 | */ 27 | Object get(Class klass, Object instance, String field); 28 | 29 | /** 30 | * Try to determine a list of fields to be serialized. Preferably without using the Class object 31 | * 32 | * @return A list of all modifiable fields on the given class, only these fields will be serialized 33 | */ 34 | List fields(Class klass, Object obj); 35 | } 36 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/serialization/mutators/ReadWriteMutator.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization.mutators; 2 | 3 | /** 4 | * A read write mutator simply merges the {@link ReadMutator} and {@link WriteMutator} 5 | * 6 | * @author Courtney Robinson 7 | */ 8 | public interface ReadWriteMutator extends ReadMutator, WriteMutator { 9 | } 10 | -------------------------------------------------------------------------------- /boson/src/main/java/io/higgs/boson/serialization/mutators/WriteMutator.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization.mutators; 2 | 3 | /** 4 | * A write mutator provides an interface for setting fields on objects without reflection 5 | * 6 | * @author Courtney Robinson 7 | */ 8 | public interface WriteMutator extends ClassMutator { 9 | 10 | /** 11 | * Sets the given field to the value provided on the instance of class T 12 | * 13 | * @param instance the instance to set the value on 14 | * @param field the field to be set 15 | * @param value the value to set the field to 16 | * @return true if successfully set 17 | * TODO: if false is returned then an attempt will be made to set the field via reflection 18 | */ 19 | boolean set(T instance, String field, Object value); 20 | 21 | /** 22 | * Given the Fully qualified class name, return an instance of the said class 23 | * 24 | * @param className the FQN 25 | * @return a new instance 26 | */ 27 | Object newInstance(String className); 28 | 29 | /** 30 | * Checks if this mutator can create instances of the given class name 31 | * 32 | * @param className The fully qualified class name 33 | * @return true if it can create new instances, false otherwise. 34 | */ 35 | boolean canCreate(String className); 36 | 37 | Enum get(String enumClassName, String enumStringName); 38 | } 39 | -------------------------------------------------------------------------------- /boson/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=DEBUG, file, stdout 3 | 4 | # Direct log messages to a log file 5 | log4j.appender.file=org.apache.log4j.RollingFileAppender 6 | log4j.appender.file.File=./var/log/higgs.log 7 | log4j.appender.file.MaxFileSize=1MB 8 | log4j.appender.file.MaxBackupIndex=1 9 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 11 | 12 | # Direct log messages to stdout 13 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 14 | log4j.appender.stdout.Target=System.out 15 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.stdout.layout.ConversionPattern=%C %d{ABSOLUTE} %5p %c{1}:%L - %m%n 17 | -------------------------------------------------------------------------------- /boson/src/test/java/io/higgs/boson/serialization/v1/CircularReferenceA.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization.v1; 2 | 3 | public class CircularReferenceA { 4 | CircularReferenceB b; 5 | 6 | public CircularReferenceA(final CircularReferenceB b) { 7 | this.b = b; 8 | } 9 | 10 | public CircularReferenceA() { 11 | //keep serializer happy 12 | } 13 | 14 | public String toString() { 15 | return hashCode() + "-A"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /boson/src/test/java/io/higgs/boson/serialization/v1/CircularReferenceB.java: -------------------------------------------------------------------------------- 1 | package io.higgs.boson.serialization.v1; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class CircularReferenceB { 7 | CircularReferenceA a; 8 | 9 | public void init() { 10 | a = new CircularReferenceA(this); 11 | } 12 | 13 | public String toString() { 14 | return hashCode() + "-B"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | core 4 | ${project.artifactId} 5 | jar 6 | Core API and interfaces for Higgs 7 | 8 | 9 | io.higgs 10 | higgs 11 | ../pom.xml 12 | 0.0.25-SNAPSHOT 13 | 14 | 15 | 16 | javax.ws.rs 17 | javax.ws.rs-api 18 | 2.0 19 | 20 | 21 | 22 | org.yaml 23 | snakeyaml 24 | 1.11 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/ConfigUtil.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | import org.yaml.snakeyaml.Yaml; 4 | import org.yaml.snakeyaml.constructor.Constructor; 5 | 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | 9 | /** 10 | * @author Courtney Robinson 11 | */ 12 | public class ConfigUtil { 13 | protected ConfigUtil() { 14 | } 15 | 16 | public static T loadYaml(String configFile, Class klass) { 17 | return loadYaml(Paths.get(configFile), klass); 18 | } 19 | 20 | public static T loadYaml(Path configFile, Class klass) { 21 | return loadYaml(configFile, klass, null); 22 | } 23 | 24 | /** 25 | * Given a path, load the file at its location as a YAML file and convert it to an instance of the given class 26 | * 27 | * @param configFile the path to the config file 28 | * @param klass the class of which to return an instance 29 | * @return an instance of the class with it's fields initialized to whatever is in the config 30 | */ 31 | public static T loadYaml(Path configFile, Class klass, Constructor constructor) { 32 | T config; 33 | Yaml yaml; 34 | if (constructor != null) { 35 | yaml = new Yaml(constructor); 36 | } else { 37 | yaml = new Yaml(); 38 | } 39 | ResolvedFile in = FileUtil.resolve(configFile); 40 | if (!in.hasStream()) { 41 | throw new ResourceNotFoundException("Unable to find config " + configFile); 42 | } 43 | try { 44 | config = yaml.loadAs(in.getStream(), klass); 45 | } catch (Throwable e) { 46 | throw new IllegalStateException(String.format("Can't load config (%s)", configFile.toAbsolutePath()), e); 47 | } 48 | return config; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/EventListenerMethod.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public interface EventListenerMethod { 7 | /** 8 | * This method is invoked after an instance of a resource has been created AND any injectable resources have been 9 | * injected. 10 | * i.e. after constructor initialization, since there is no way to inject field values before calling 11 | * the constructor. 12 | */ 13 | void init(); 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/FileUtil.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | import java.io.File; 4 | import java.nio.file.Path; 5 | import java.nio.file.Paths; 6 | 7 | /** 8 | * @author Courtney Robinson 9 | */ 10 | public class FileUtil { 11 | public static final String PATH_SEPARATOR = System.getProperty("file.separator"); 12 | 13 | protected FileUtil() { 14 | } 15 | 16 | public static ResolvedFile resolve(String baseDir, String file) { 17 | return resolve(baseDir == null ? null : Paths.get(baseDir), file == null ? null : Paths.get(file)); 18 | } 19 | 20 | /** 21 | * Given a path, try locating the file/directory represented by it. 22 | * First check the file system, then check class path. 23 | * In both cases the path must be a child of the base directory provided. 24 | * The file system is checked first because some resources such as configs usually 25 | * can't be packaged within a JAR because they need to be updated etc... 26 | * 27 | * @param baseDir an optional base directory to use. If this is null then the file's path is used directly 28 | * otherwise the file's path is resolved against this base directory 29 | * @param file the file to get an input stream for 30 | * @return An input stream to consume data from the file or null if the file cannot be found 31 | */ 32 | public static ResolvedFile resolve(Path baseDir, Path file) { 33 | if (file == null) { 34 | throw new IllegalArgumentException("Path cannot be null or empty"); 35 | } 36 | ResolvedFile ret = new ResolvedFile(); 37 | if (baseDir != null) { 38 | file = baseDir.resolve(file); 39 | } 40 | ret.setPath(file, baseDir); 41 | return ret; 42 | } 43 | 44 | public static ResolvedFile resolve(File file) { 45 | if (file == null) { 46 | return null; 47 | } 48 | return resolve(file.toPath()); 49 | } 50 | 51 | public static ResolvedFile resolve(Path file) { 52 | return resolve(null, file); 53 | } 54 | 55 | public static ResolvedFile resolve(Path base, File file) { 56 | if (file == null) { 57 | return null; 58 | } 59 | return resolve(base, file.toPath()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/FixedSortedList.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.Collections; 6 | import java.util.Comparator; 7 | 8 | /** 9 | * A list which sorts the items it is created with. 10 | * Sort order is not maintained. 11 | * 12 | * @author Courtney Robinson 13 | */ 14 | public class FixedSortedList extends ArrayList implements Comparator> { 15 | /** 16 | * Create a new list and sort the provided parameters 17 | * 18 | * @param set the collection to sort 19 | */ 20 | public FixedSortedList(Collection set) { 21 | super(set); 22 | Collections.sort(this, (Comparator) this); 23 | } 24 | 25 | @Override 26 | public int compare(Sortable a, Sortable b) { 27 | return a.priority() > b.priority() ? -1 : (a.priority() == b.priority() ? 0 : 1); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/HiggsInterceptor.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | /** 6 | * A request interceptor provides a way for an incoming request to be handled by a the same or a 7 | * completely different {@link MessageHandler}. 8 | * 9 | * @author Courtney Robinson 10 | */ 11 | public interface HiggsInterceptor { 12 | /** 13 | * An interceptor should provide a set of patterns where, if matched and the incoming request is of 14 | * the class type corresponding to a matched pattern the 15 | * {@link #intercept(io.netty.channel.ChannelHandlerContext, Object)} method is called passing the request 16 | * object and the matched pattern. Once a pattern is matched no further action is taken to process 17 | * the request unless the intercept method returns false, indicating it was not able to process the 18 | * request. 19 | * One might store a set of patterns to be matched in the form {@code Map>} 20 | * 21 | * @return true if, using its set of patterns this request can be handled. 22 | */ 23 | boolean matches(Object msg); 24 | 25 | /** 26 | * Invoked when one of the patterns provided by this interceptor matches. 27 | * 28 | * @param request The incoming request to be intercepted 29 | * @return true if the interceptor is successfully able to process the request false otherwise. 30 | * If false is returned the request may be passed to another interceptor or left to the origin 31 | * {@link MessageHandler} 32 | */ 33 | boolean intercept(ChannelHandlerContext ctx, Object request); 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/MethodProcessor.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.Queue; 5 | 6 | /** 7 | * @author Courtney Robinson 8 | */ 9 | public interface MethodProcessor { 10 | /** 11 | * Given the set of parameters, construct an {@link InvokableMethod} 12 | * 13 | * @param method the Java class method which is to be processed 14 | * @param klass the class to which the method belongs 15 | * @param factories a factories, which are registered with the server 16 | * @return an invokable method 17 | */ 18 | T process(Method method, Class klass, Queue factories); 19 | 20 | /** 21 | * Used to create new instances of the {@link io.higgs.core.InvokableMethod} this process handles 22 | */ 23 | T newMethod(Method method, Class klass, Queue factories); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/ObjectFactory.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | /** 4 | * An object factories is responsible for creating instances of various objects. 5 | * 6 | * @author Courtney Robinson 7 | */ 8 | public abstract class ObjectFactory { 9 | private final HiggsServer server; 10 | 11 | public ObjectFactory(HiggsServer server) { 12 | this.server = server; 13 | } 14 | 15 | public abstract Object newInstance(Class klass); 16 | 17 | public abstract boolean canCreateInstanceOf(Class klass); 18 | 19 | public HiggsServer getServer() { 20 | return server; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/ParameterExtractor.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public interface ParameterExtractor { 9 | Object[] extractParams(ChannelHandlerContext ctx, String path, Object msg); 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/ProtocolConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public interface ProtocolConfiguration { 7 | ProtocolDetectorFactory getProtocol(); 8 | 9 | MethodProcessor getMethodProcessor(); 10 | 11 | /** 12 | * Invoked before any other method is called on the protocol implementation. 13 | * 14 | * @param server the server instance this protocol is being registered to 15 | */ 16 | void initialize(HiggsServer server); 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/ProtocolDetector.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelPipeline; 6 | 7 | /** 8 | * @author Courtney Robinson 9 | */ 10 | public interface ProtocolDetector { 11 | /** 12 | * Using the data available in {@param #in} check if the data matches the protocol this detector represents 13 | * 14 | * @param ctx the channel context 15 | * @param in data available 16 | * @return true if the protocol matches, false otherwise 17 | */ 18 | boolean detected(ChannelHandlerContext ctx, ByteBuf in); 19 | 20 | /** 21 | * Set up the pipeline adding a {@link io.netty.handler.codec.ByteToMessageDecoder } and 22 | * a {@link io.netty.handler.codec.MessageToByteEncoder} as necessary 23 | * 24 | * @param p the pipeline to add handlers to 25 | * @param ctx the context for the channel 26 | */ 27 | MessageHandler setupPipeline(ChannelPipeline p, ChannelHandlerContext ctx); 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/ProtocolDetectorFactory.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | /** 4 | * To support shared state encoders, decoders and {@link ProtocolDetector}s a {@link ProtocolDetectorFactory} 5 | * is used as a factories to create new instances of each for every channel. 6 | * 7 | * @author Courtney Robinson 8 | */ 9 | public interface ProtocolDetectorFactory extends Sortable { 10 | 11 | /** 12 | * Provide a new instance of the {@link ProtocolDetector} this codec represents 13 | * Very important that a new instance is provided each time. If the same one is returned it will be used by multiple 14 | * threads. 15 | * 16 | * @return A new ProtocolDetector 17 | */ 18 | ProtocolDetector newProtocolDetector(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/ResourceNotFoundException.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class ResourceNotFoundException extends RuntimeException { 7 | public ResourceNotFoundException(String format) { 8 | super(format); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/ServerConfig.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class ServerConfig { 7 | /** 8 | * If true then a new instance of resource classes are created for every request the class matches 9 | * if false then a single instance is used to service every request. 10 | * useful for concurrency issues 11 | */ 12 | public boolean instance_per_request = true; 13 | /** 14 | * the port the server binds to 15 | */ 16 | public int port = 8080; 17 | public String session_path = "/", session_dir = "/tmp/hs3-sessions/"; 18 | //ignored if null 19 | public String session_domain; 20 | //7 days in milliseconds 21 | public long session_max_age = 604800000; 22 | public boolean session_http_only; 23 | //ignored if null 24 | public String session_ports; 25 | public String default_error_template = "error/default"; 26 | public boolean add_default_injector = true; 27 | public boolean add_static_resource_filter = true; 28 | public boolean log_requests = true; 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/Sortable.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | /** 4 | * Sortable objects are used in {@link java.util.TreeSet}s. 5 | * The larger the priority the closer the object is to the front of the queue 6 | */ 7 | public interface Sortable extends Comparable { 8 | /** 9 | * Sets the priority of this sortable object 10 | * 11 | * @param value the new value 12 | * @return the old priority 13 | */ 14 | int setPriority(int value); 15 | 16 | /** 17 | * Gets the current priority of this sortable object 18 | * 19 | * @return the current priority 20 | */ 21 | int priority(); 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/StaticUtil.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelHandlerContext; 6 | 7 | /** 8 | * @author Courtney Robinson 9 | */ 10 | public final class StaticUtil { 11 | private StaticUtil() { 12 | } 13 | 14 | public static ChannelFuture write(Channel channel, Object o) { 15 | return channel.writeAndFlush(o); 16 | } 17 | 18 | public static ChannelFuture write(ChannelHandlerContext ctx, Object o) { 19 | return ctx.writeAndFlush(o); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/func/Function.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core.func; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public interface Function { 7 | void apply(); 8 | } 9 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/func/Function1.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core.func; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public interface Function1 { 7 | void apply(A a); 8 | } 9 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/func/Function2.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core.func; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public interface Function2 { 7 | void apply(A a, B b); 8 | } 9 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/reflect/ReflectionUtil.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core.reflect; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | import java.util.Collections; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | public final class ReflectionUtil { 10 | public static int MAX_RECURSION_DEPTH = 10; 11 | 12 | private ReflectionUtil() { 13 | } 14 | 15 | public static Set getAllFields(Set fields, Class type) { 16 | return getAllFields(fields, type, 0); 17 | } 18 | 19 | public static Set getAllFields(Set fields, Class type, int depth) { 20 | //first get inherited fields 21 | if (type.getSuperclass() != null && depth <= MAX_RECURSION_DEPTH) { 22 | getAllFields(fields, type.getSuperclass(), ++depth); 23 | } 24 | //now add all "local" fields 25 | Collections.addAll(fields, type.getDeclaredFields()); 26 | return fields; 27 | } 28 | 29 | public static Method[] getAllMethods(Class klass) { 30 | HashSet methods = new HashSet<>(); 31 | getAllMethods(methods, klass); 32 | return methods.toArray(new Method[methods.size()]); 33 | } 34 | 35 | public static Set getAllMethods(Set methods, Class type) { 36 | return getAllMethods(methods, type, 0); 37 | } 38 | 39 | public static Set getAllMethods(Set methods, Class type, int depth) { 40 | if (type.getSuperclass() != null && depth <= MAX_RECURSION_DEPTH) { 41 | getAllMethods(methods, type.getSuperclass(), ++depth); 42 | } 43 | Collections.addAll(methods, type.getDeclaredMethods()); 44 | return methods; 45 | } 46 | 47 | /** 48 | * @param klass 49 | * @return true if klass represents a numeric type, including byte. Both boxed and unboxed. 50 | */ 51 | public static boolean isNumeric(Class klass) { 52 | return Integer.class.isAssignableFrom(klass) || 53 | int.class.isAssignableFrom(klass) || 54 | Long.class.isAssignableFrom(klass) || 55 | long.class.isAssignableFrom(klass) || 56 | Double.class.isAssignableFrom(klass) || 57 | double.class.isAssignableFrom(klass) || 58 | Float.class.isAssignableFrom(klass) || 59 | float.class.isAssignableFrom(klass) || 60 | Short.class.isAssignableFrom(klass) || 61 | Short.class.isAssignableFrom(klass) || 62 | Byte.class.isAssignableFrom(klass) || 63 | byte.class.isAssignableFrom(klass); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/reflect/classpath/CachedPath.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core.reflect.classpath; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class CachedPath { 7 | private final String className; 8 | private String filename, path; 9 | private boolean isJar; 10 | private String separator = System.getProperty("file.separator"); 11 | 12 | CachedPath(String filename, String path, boolean jar) { 13 | String className = filename; 14 | if (className.startsWith(path)) { 15 | //remove the directory or jar path from the class name 16 | className = className.substring(path.length()); 17 | } 18 | if (className.startsWith(separator)) { 19 | className = className.substring(1); //replace start / first 20 | } 21 | className = className.replace(separator.charAt(0), '.'); //now replace all other slashes 22 | 23 | if (className.endsWith(".class")) { 24 | className = className.substring(0, className.length() - 6); 25 | } 26 | this.className = className; 27 | this.filename = filename; 28 | this.path = path; 29 | isJar = jar; 30 | } 31 | 32 | /** 33 | * @return The full path to the file e.g. com/domain/product/MyClass.class 34 | */ 35 | public String getFilename() { 36 | return filename; 37 | } 38 | 39 | public void setFilename(final String filename) { 40 | this.filename = filename; 41 | } 42 | 43 | /** 44 | * @return Fully qualified class name e.g. com.domain.product.MyClass 45 | */ 46 | public String getClassName() { 47 | return className; 48 | } 49 | 50 | /** 51 | * @return The path to the package or jar containing this file 52 | */ 53 | public String getPath() { 54 | return path; 55 | } 56 | 57 | public void setPath(final String path) { 58 | this.path = path; 59 | } 60 | 61 | public boolean isJar() { 62 | return isJar; 63 | } 64 | 65 | public void setJar(final boolean jar) { 66 | isJar = jar; 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return "CachedPath{" + 72 | "filename='" + filename + '\'' + 73 | ", path='" + path + '\'' + 74 | ", isJar=" + isJar + 75 | '}'; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /core/src/main/java/io/higgs/core/ssl/SSLConfigFactory.java: -------------------------------------------------------------------------------- 1 | package io.higgs.core.ssl; 2 | 3 | import java.lang.management.ManagementFactory; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class SSLConfigFactory { 9 | public static final SSLConfiguration sslConfiguration = new SSLConfiguration(); 10 | 11 | protected SSLConfigFactory() { 12 | } 13 | 14 | static { 15 | for (String arg : ManagementFactory.getRuntimeMXBean().getInputArguments()) { 16 | String[] kv = arg.split("="); 17 | if (kv.length >= 2) { 18 | String name = kv[0]; 19 | String value = kv[1]; 20 | switch (name) { 21 | case "javax.net.ssl.keyStore": 22 | sslConfiguration.setKeyStorePath(value); 23 | case "javax.net.ssl.keyStorePassword": 24 | sslConfiguration.setKeyStorePassword(value); 25 | case "javax.net.ssl.trustStrore": 26 | sslConfiguration.setTrustStorePath(value); 27 | case "javax.net.ssl.trustStorePassword": 28 | sslConfiguration.setTrustStorePassword(value); 29 | case "javax.net.ssl.keyPassword": 30 | sslConfiguration.setKeyPassword(value); 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=DEBUG, file, stdout 3 | 4 | # Direct log messages to a log file 5 | log4j.appender.file=org.apache.log4j.RollingFileAppender 6 | log4j.appender.file.File=./log/higgs.log 7 | log4j.appender.file.MaxFileSize=1MB 8 | log4j.appender.file.MaxBackupIndex=1 9 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 11 | 12 | # Direct log messages to stdout 13 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 14 | log4j.appender.stdout.Target=System.out 15 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.stdout.layout.ConversionPattern=%C %d{ABSOLUTE} %5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /events/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | events 4 | ${project.artifactId} 5 | Higgs Events 6 | jar 7 | 8 | io.higgs 9 | higgs 10 | ../pom.xml 11 | 0.0.25-SNAPSHOT 12 | 13 | 14 | 15 | io.higgs 16 | core 17 | ${project.version} 18 | 19 | 20 | 21 | 22 | 23 | boundary-site 24 | http://maven.boundary.com/artifactory/repo 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/Event.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public interface Event { 7 | String name(); 8 | } 9 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/EventHandler.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events; 2 | 3 | import io.higgs.core.InvokableMethod; 4 | import io.higgs.core.reflect.dependency.DependencyProvider; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.SimpleChannelInboundHandler; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.util.Queue; 11 | 12 | /** 13 | * @author Courtney Robinson 14 | */ 15 | public class EventHandler extends SimpleChannelInboundHandler { 16 | private final Queue methods; 17 | private Logger log = LoggerFactory.getLogger(getClass()); 18 | 19 | public EventHandler(Queue methods) { 20 | this.methods = methods; 21 | } 22 | 23 | @Override 24 | public void channelRead0(ChannelHandlerContext ctx, EventMessage msg) throws Exception { 25 | int matches = 0; 26 | for (InvokableMethod method : methods) { 27 | if (method.matches(msg.name(), ctx, msg)) { 28 | Object response = method.invoke(ctx, msg.name(), msg, msg.params(), DependencyProvider.from()); 29 | if (response instanceof TypeMismatch) { 30 | continue; 31 | } 32 | matches++; 33 | } 34 | } 35 | if (matches == 0) { 36 | log.debug(String.format("Event received but no subscribers found (%s)", msg)); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/EventMessage.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class EventMessage { 9 | private final Object[] params; 10 | private final String name; 11 | private final String str; 12 | 13 | public EventMessage(String event, Object[] params) { 14 | this.name = event; 15 | this.params = params; 16 | str = "Event{" + 17 | "name='" + name + '\'' + 18 | ", params=" + Arrays.toString(params) + 19 | '}'; 20 | } 21 | 22 | /** 23 | * @return the name of this event 24 | */ 25 | public String name() { 26 | return name; 27 | } 28 | 29 | /** 30 | * @return the set of arguments emitted with this event 31 | */ 32 | public Object[] params() { 33 | return params; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return str; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/EventMethod.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events; 2 | 3 | import io.higgs.core.InvokableMethod; 4 | import io.higgs.core.ObjectFactory; 5 | import io.netty.channel.ChannelHandlerContext; 6 | 7 | import java.lang.reflect.Method; 8 | import java.util.Queue; 9 | 10 | /** 11 | * @author Courtney Robinson 12 | */ 13 | public class EventMethod extends InvokableMethod { 14 | public EventMethod(Queue factories, Class klass, Method classMethod) { 15 | super(factories, klass, classMethod); 16 | } 17 | 18 | public void registered() { 19 | log.info(String.format("REGISTERED > %1$-20s | %2$-30s | %3$-50s", classMethod.getName(), 20 | path(), classMethod.getReturnType().getName())); 21 | } 22 | 23 | @Override 24 | public boolean matches(String path, ChannelHandlerContext ctx, Object msg) { 25 | return path().matches(path); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/EventMethodProcessor.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events; 2 | 3 | import io.higgs.core.MethodProcessor; 4 | import io.higgs.core.ObjectFactory; 5 | 6 | import java.lang.reflect.Method; 7 | import java.util.Queue; 8 | 9 | /** 10 | * @author Courtney Robinson 11 | */ 12 | public class EventMethodProcessor implements MethodProcessor { 13 | @Override 14 | public EventMethod process(Method method, Class klass, Queue factories) { 15 | return newMethod(method, klass, factories); 16 | } 17 | 18 | @Override 19 | public EventMethod newMethod(Method method, Class klass, Queue factories) { 20 | return new EventMethod(factories, klass, method); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/EventServer.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events; 2 | 3 | import io.higgs.core.HiggsServer; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.local.LocalAddress; 6 | import io.netty.channel.local.LocalChannel; 7 | import io.netty.channel.local.LocalEventLoopGroup; 8 | import io.netty.channel.local.LocalServerChannel; 9 | 10 | /** 11 | * @author Courtney Robinson 12 | */ 13 | public class EventServer extends HiggsServer { 14 | protected final LocalAddress address; 15 | 16 | public EventServer(LocalAddress address) { 17 | this.address = address; 18 | bossGroup = new LocalEventLoopGroup(); 19 | } 20 | 21 | /** 22 | * Start the server causing it to bind to the provided {@link #port} 23 | * 24 | * @throws UnsupportedOperationException if the server's already started 25 | */ 26 | public void start() { 27 | if (channel != null) { 28 | throw new UnsupportedOperationException("Server already started"); 29 | } 30 | try { 31 | bootstrap 32 | .group(bossGroup) 33 | .channel(LocalServerChannel.class) 34 | .handler(new ChannelInitializer() { 35 | public void initChannel(LocalServerChannel ch) throws Exception { 36 | // ch.pipeline().addLast(new LoggingHandler(LogLevel.ERROR)); 37 | } 38 | }) 39 | .childHandler(new ChannelInitializer() { 40 | @Override 41 | public void initChannel(LocalChannel ch) throws Exception { 42 | ch.pipeline().addLast(new EventHandler(methods)); 43 | } 44 | }); 45 | 46 | // Bind and start to accept incoming connections. 47 | channel = bootstrap.bind(address).sync().channel(); 48 | } catch (Throwable t) { 49 | log.warn("Error starting server", t); 50 | } 51 | } 52 | 53 | public void registerMethod(FunctionEventMethod method) { 54 | methods.add(method); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/FunctionEventMethod.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events; 2 | 3 | import io.higgs.core.ObjectFactory; 4 | import io.higgs.core.func.Function1; 5 | import io.higgs.core.reflect.dependency.DependencyProvider; 6 | import io.netty.channel.ChannelHandlerContext; 7 | 8 | import java.lang.reflect.InvocationTargetException; 9 | import java.util.LinkedList; 10 | 11 | /** 12 | * @author Courtney Robinson 13 | */ 14 | public class FunctionEventMethod extends EventMethod { 15 | private final Function1 function; 16 | 17 | public FunctionEventMethod(String event, Function1 function) { 18 | //dummy values, the invoke method is overriden so these aren't used 19 | super(new LinkedList(), Function1.class, 20 | Function1.class.getMethods()[0]); 21 | this.function = function; 22 | path = event; 23 | } 24 | 25 | public boolean matches(String path, ChannelHandlerContext ctx, Object msg) { 26 | try { 27 | return path.matches(path); 28 | } catch (ClassCastException cce) { 29 | return false; 30 | } 31 | } 32 | 33 | //won't use normal dependency injection because it only supports 1 parameter 34 | public Object invoke(ChannelHandlerContext ctx, String path, Object msg, Object[] params, 35 | DependencyProvider provider) 36 | throws InvocationTargetException, IllegalAccessException, InstantiationException { 37 | try { 38 | Object param = null; 39 | if (params.length > 0) { 40 | param = params[0]; 41 | } 42 | function.apply((A) param); 43 | } catch (ClassCastException cce) { 44 | return new TypeMismatch(cce); 45 | } 46 | return null; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/SingletonFactory.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events; 2 | 3 | import io.higgs.core.HiggsServer; 4 | import io.higgs.core.ObjectFactory; 5 | 6 | /** 7 | * @author Courtney Robinson 8 | */ 9 | public class SingletonFactory extends ObjectFactory { 10 | private final Object instance; 11 | private final Class klass; 12 | 13 | public SingletonFactory(HiggsServer server, Object instance) { 14 | super(server); 15 | this.instance = instance; 16 | klass = instance.getClass(); 17 | server.registerClass(klass); 18 | } 19 | 20 | @Override 21 | public Object newInstance(Class klass) { 22 | return instance; 23 | } 24 | 25 | @Override 26 | public boolean canCreateInstanceOf(Class klass) { 27 | return this.klass.isAssignableFrom(klass); 28 | } 29 | 30 | /** 31 | * @return the instance represented by this singleton factory 32 | */ 33 | public Object instance() { 34 | return instance; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/Task.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events; 2 | 3 | import io.higgs.core.func.Function; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public interface Task extends Function { 9 | } 10 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/TypeMismatch.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class TypeMismatch { 7 | private final ClassCastException exception; 8 | 9 | public TypeMismatch(ClassCastException cce) { 10 | exception = cce; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/demo/ClassExample.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events.demo; 2 | 3 | import io.higgs.events.EventMessage; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.util.concurrent.EventExecutor; 7 | 8 | import javax.ws.rs.Path; 9 | 10 | /** 11 | * @author Courtney Robinson 12 | */ 13 | public class ClassExample { 14 | /** 15 | * This will be injected before the method is invoked. 16 | * One method is invoked per instance 17 | */ 18 | private EventExecutor instanceExecutor; 19 | 20 | public ClassExample() { 21 | //instanceExecutor will be null in the constructor but will be injected after construction 22 | } 23 | 24 | public void init() { 25 | //if init method exists it'll be called, use in place of constructor 26 | //all injectable fields will be injected at this point 27 | System.out.println("init, instanceInject!=null -->" + (instanceExecutor != null)); 28 | } 29 | 30 | /** 31 | * ctx,channel and event can appear at any location in the list of parameters 32 | * but the order of other parameters must match the order of parameters emitted 33 | * in this case, Events.emit("test","some string",100) must be the order 34 | *

35 | * doing this would fail Events.emit("test",100,"some string") 36 | * Imagine a method that has parameters (int,int,String,String) 37 | * if the order wasn't enforced when something like 38 | * Events.emit(1,2,"a","b") is emitted then b could go in place of a or 1 in place of 2 39 | * 40 | * @param ctx the channel context, each event has 1 context which is paired with an 41 | * event name, in this case "test" so all test events emitted will have the same context 42 | * @param channel like channel context there is 1 channel per event 43 | * @param eventMessage every time the test event is emitted a new {@link io.higgs.events.EventMessage} object 44 | * will be created 45 | * @param executor submit background tasks to the executor 46 | */ 47 | @Path("test") //subscribe to events emitted with the name "test" 48 | public void test( 49 | ChannelHandlerContext ctx, 50 | String a, 51 | Channel channel, 52 | int b, 53 | EventMessage eventMessage, 54 | RandomObject object, 55 | EventExecutor executor) { 56 | System.out.println( 57 | Thread.currentThread().getName() + 58 | ":First test subscriber :" + a + " " + b 59 | ); 60 | //executor.schedule() //schedule a background task 61 | //executor.scheduleAtFixedRate() 62 | //executor.submit() //runnable 63 | //etc 64 | } 65 | 66 | @Path("test") 67 | public void test2(String a, int b) { 68 | System.out.println( 69 | Thread.currentThread().getName() + 70 | ": Second test subscriber :" + a + " " + b 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/demo/Demo.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events.demo; 2 | 3 | import io.higgs.core.func.Function1; 4 | import io.higgs.events.Events; 5 | import io.netty.channel.ChannelFuture; 6 | import io.netty.util.concurrent.GenericFutureListener; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * @author Courtney Robinson 12 | */ 13 | public final class Demo { 14 | private Demo() { 15 | } 16 | 17 | public static void main(String... args) throws IOException { 18 | // if you really must completely isolate events then use Events.group("group-name"); 19 | //but each call to Events.group creates a fresh set of resources... 20 | //too much and you'll run out of memory - i.e it's rare you'll need to 21 | //Events.get() is multi-threaded 22 | Events events = Events.get(); 23 | 24 | //subscribe this class' methods 25 | events.subscribe(ClassExample.class); 26 | 27 | //subscribe all eligible classes (including those in sub packages of this package) 28 | events.subscribeAll(Events.class.getPackage()); 29 | //subscribe an instance - as many instances can be registered as you want 30 | // event instances of the same class (but they'll all be invoked if the event topic matches)... 31 | events.subscribe(new ClassExample()); 32 | //subscribe this function to these events execute this function 33 | events.on(new Function1() { 34 | public void apply(String s) { 35 | System.out.println(Thread.currentThread().getName() + " Event received : " + s); 36 | } 37 | }, "event-name", "test", "event3"); 38 | 39 | events.emit("event-name", "event name topic"); 40 | 41 | for (int i = 0; i < 10; i++) { 42 | //both ClassExample.test and the function above subscribe to the topic "test" 43 | // so both will be invoked but the function will only get the first parameter 44 | //where as the class's method accepts a string,int,RandomObject so will get all 45 | ChannelFuture f = events.emit("test", "test event", i, new RandomObject(i)); 46 | f.addListener(new GenericFutureListener() { 47 | @Override 48 | public void operationComplete(ChannelFuture future) throws Exception { 49 | System.out.println("Completed"); 50 | if (future.isSuccess()) { 51 | System.out.println("Emitted "); 52 | } else { 53 | future.cause().printStackTrace(); 54 | } 55 | } 56 | }); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /events/src/main/java/io/higgs/events/demo/RandomObject.java: -------------------------------------------------------------------------------- 1 | package io.higgs.events.demo; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class RandomObject { 7 | private final int val; 8 | 9 | public RandomObject(int i) { 10 | this.val = i; 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return "RandomObject{" + 16 | "val=" + val + 17 | '}'; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /events/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, file, stdout 3 | 4 | # Direct log messages to a log file 5 | log4j.appender.file=org.apache.log4j.RollingFileAppender 6 | log4j.appender.file.File=./var/log/events.log 7 | log4j.appender.file.MaxFileSize=100MB 8 | log4j.appender.file.MaxBackupIndex=5 9 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 11 | 12 | # Direct log messages to stdout 13 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 14 | log4j.appender.stdout.Target=System.out 15 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.stdout.layout.ConversionPattern=%C %d{ABSOLUTE} %5p %c{1}:%L - %m%n 17 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Higgs Examples 2 | 3 | Having working examples helps ease the learning process to any new library. 4 | This module includes working examples that demonstrates various features of Higgs 5 | -------------------------------------------------------------------------------- /examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | examples 4 | ${project.artifactId} 5 | Higgs Examples 6 | jar 7 | 8 | io.higgs 9 | higgs 10 | ../pom.xml 11 | 0.0.25-SNAPSHOT 12 | 13 | 14 | 15 | io.higgs 16 | http-s3 17 | 18 | 19 | io.higgs 20 | http-client 21 | 22 | 23 | io.higgs 24 | events 25 | 26 | 27 | io.higgs 28 | ws-client 29 | 30 | 31 | io.higgs 32 | ws-server 33 | 34 | 35 | io.higgs 36 | boson 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /examples/src/main/java/io/higgs/examples/boson/DemoClient.java: -------------------------------------------------------------------------------- 1 | package io.higgs.examples.boson; 2 | 3 | import io.higgs.boson.serialization.mutators.ReadMutator; 4 | import io.higgs.boson.serialization.mutators.WriteMutator; 5 | import io.higgs.boson.serialization.v1.BosonReader; 6 | import io.higgs.boson.serialization.v1.BosonWriter; 7 | import io.netty.buffer.ByteBuf; 8 | 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | /** 13 | * @author Courtney Robinson 14 | */ 15 | public class DemoClient { 16 | protected DemoClient() { 17 | } 18 | 19 | public static void main(String... args) { 20 | Set writeMutators = new HashSet<>(); 21 | Set readMutators = new HashSet<>(); 22 | 23 | // 24 | PoloExample poloExample = new PoloExample(); 25 | Nested nested = new Nested(); 26 | // 27 | BosonWriter writer = new BosonWriter(readMutators); 28 | BosonReader reader = new BosonReader(writeMutators); 29 | 30 | ByteBuf serializedPolo = writer.serialize(poloExample); 31 | PoloExample deserializedPolo = reader.deSerialize(serializedPolo); 32 | 33 | System.out.println(poloExample); 34 | System.out.println(deserializedPolo); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/src/main/java/io/higgs/examples/boson/Nested.java: -------------------------------------------------------------------------------- 1 | package io.higgs.examples.boson; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | 8 | public class Nested { 9 | NestedField[] array = new NestedField[]{ new NestedField(), new NestedField(), new NestedField() }; 10 | List list = Arrays.asList("a", "b", "c", "d"); 11 | 12 | public String toString() { 13 | StringBuilder buf = new StringBuilder(); 14 | buf.append("["); 15 | for (Field field : getClass().getDeclaredFields()) { 16 | field.setAccessible(true); 17 | Object value = null; 18 | try { 19 | value = field.get(this); 20 | } catch (IllegalAccessException e) { 21 | //bleh! 22 | } 23 | if (field.getType().isArray()) { 24 | buf.append(field.getName()).append(" = "); 25 | for (Object v : (Object[]) value) { 26 | buf.append(v).append(","); 27 | } 28 | } else { 29 | buf.append(field.getName()).append(" = ").append(value); 30 | } 31 | buf.append(",\n"); 32 | } 33 | buf.append("]"); 34 | return buf.toString(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/src/main/java/io/higgs/examples/boson/NestedField.java: -------------------------------------------------------------------------------- 1 | package io.higgs.examples.boson; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | public class NestedField { 8 | int a; 9 | long b; 10 | double c; 11 | float d; 12 | Map map = new HashMap(); 13 | 14 | public NestedField() { 15 | map.put("a", 2); 16 | map.put(1, "123"); 17 | } 18 | 19 | public String toString() { 20 | StringBuilder buf = new StringBuilder(); 21 | buf.append("["); 22 | for (Field field : getClass().getDeclaredFields()) { 23 | field.setAccessible(true); 24 | Object value = null; 25 | try { 26 | value = field.get(this); 27 | } catch (IllegalAccessException e) { 28 | //bleh! 29 | } 30 | if (field.getType().isArray()) { 31 | buf.append(field.getName()).append(" = "); 32 | for (Object v : (Object[]) value) { 33 | buf.append(v).append(","); 34 | } 35 | } else { 36 | buf.append(field.getName()).append(" = ").append(value); 37 | } 38 | buf.append(",\n"); 39 | } 40 | buf.append("]"); 41 | return buf.toString(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/src/main/java/io/higgs/examples/boson/PoloExample.java: -------------------------------------------------------------------------------- 1 | package io.higgs.examples.boson; 2 | 3 | import io.higgs.boson.serialization.BosonProperty; 4 | 5 | import java.lang.reflect.Field; 6 | 7 | public class PoloExample { 8 | public static boolean dont = true; 9 | public static boolean stillDont; 10 | @BosonProperty 11 | int i; 12 | String name = "Test non-annotated field"; 13 | @BosonProperty(ignore = true) 14 | String ignored; 15 | Nested nested = new Nested(); 16 | private String str = "Test private non-annotated field"; 17 | 18 | public PoloExample() { 19 | } 20 | 21 | public PoloExample(int j) { 22 | i = j; 23 | } 24 | 25 | public String toString() { 26 | StringBuilder buf = new StringBuilder(); 27 | buf.append("["); 28 | for (Field field : getClass().getDeclaredFields()) { 29 | field.setAccessible(true); 30 | Object value = null; 31 | try { 32 | value = field.get(this); 33 | } catch (IllegalAccessException e) { 34 | //bleh! 35 | } 36 | if (field.getType().isArray()) { 37 | buf.append(field.getName()).append(" = "); 38 | for (Object v : (Object[]) value) { 39 | buf.append(v).append(","); 40 | } 41 | } else { 42 | buf.append(field.getName()).append(" = ").append(value); 43 | } 44 | buf.append(",\n"); 45 | } 46 | buf.append("]"); 47 | return buf.toString(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /examples/src/main/java/io/higgs/examples/httpServer/restService/Demo.java: -------------------------------------------------------------------------------- 1 | package io.higgs.examples.httpServer.restService; 2 | 3 | import io.higgs.core.HiggsServer; 4 | import io.higgs.http.server.Transcription; 5 | import io.higgs.http.server.config.HttpConfig; 6 | import io.higgs.http.server.protocol.HttpProtocolConfiguration; 7 | 8 | /** 9 | * @author Courtney Robinson 10 | */ 11 | public final class Demo { 12 | private Demo() { 13 | } 14 | 15 | public static void main(String... args) { 16 | 17 | HttpProtocolConfiguration http = new HttpProtocolConfiguration(); 18 | //re-write all requests to /app/* to index.html 19 | http.getTranscriber().addTranscription(new Transcription("/app((?:\\/[\\w([^\\..]{1,4}\b)\\-]+)+)", 20 | "/index.html")); 21 | HiggsServer server = new HiggsServer().setConfig("config.yml", HttpConfig.class); 22 | server.registerProtocol(http); 23 | // 24 | server.registerPackage(Api.class.getPackage()); 25 | // server.registerClass(Api.class); 26 | // server.registerObject(new Api()); 27 | server.start(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/src/main/java/io/higgs/examples/websocketServer/Api.java: -------------------------------------------------------------------------------- 1 | package io.higgs.examples.websocketServer; 2 | 3 | import io.higgs.ws.JsonRequest; 4 | import io.higgs.ws.protocol.WebSocketConfiguration; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelHandlerContext; 7 | 8 | import javax.ws.rs.Path; 9 | 10 | /** 11 | * @author Courtney Robinson 12 | */ 13 | @Path("/ws") 14 | public class Api { 15 | 16 | @Path("test/{string:[a-z0-9]+}/{num:[0-9]+}") 17 | public Object test( 18 | JsonRequest request, 19 | ChannelHandlerContext ctx, 20 | Channel channel, 21 | WebSocketConfiguration configuration, 22 | Pojo pojo 23 | ) { 24 | return request; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/src/main/java/io/higgs/examples/websocketServer/Pojo.java: -------------------------------------------------------------------------------- 1 | package io.higgs.examples.websocketServer; 2 | 3 | /** 4 | * Random POJO class 5 | * 6 | * @author Courtney Robinson 7 | */ 8 | public class Pojo { 9 | public int d = 1; 10 | } 11 | -------------------------------------------------------------------------------- /examples/src/main/java/io/higgs/examples/websocketServer/WebSocketDemo.java: -------------------------------------------------------------------------------- 1 | package io.higgs.examples.websocketServer; 2 | 3 | import io.higgs.core.HiggsServer; 4 | import io.higgs.http.server.Transcription; 5 | import io.higgs.http.server.config.HttpConfig; 6 | import io.higgs.http.server.protocol.HttpProtocolConfiguration; 7 | import io.higgs.ws.protocol.WebSocketConfiguration; 8 | 9 | /** 10 | * @author Courtney Robinson 11 | */ 12 | public final class WebSocketDemo { 13 | private WebSocketDemo() { 14 | } 15 | 16 | public static void main(String... args) { 17 | //handles HTTP GET requests 18 | WebSocketConfiguration ws = new WebSocketConfiguration(); 19 | //handles all other HTTP requests 20 | HttpProtocolConfiguration http = new HttpProtocolConfiguration(); 21 | //re-write all requests to /app/* to index.html 22 | ws.getTranscriber().addTranscription(new Transcription("/app((?:\\/[\\w([^\\..]{1,4}\b)\\-]+)+)", 23 | "/index.html")); 24 | 25 | HiggsServer server = new HiggsServer().setConfig("config.yml", HttpConfig.class); 26 | server.registerProtocol(ws); 27 | //HTTP must be registered after WebSockets 28 | server.registerProtocol(http); 29 | // 30 | server.registerClass(Api.class); 31 | server.start(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, file, stdout 3 | 4 | # Direct log messages to a log file 5 | log4j.appender.file=org.apache.log4j.RollingFileAppender 6 | log4j.appender.file.File=./var/log/events.log 7 | log4j.appender.file.MaxFileSize=100MB 8 | log4j.appender.file.MaxBackupIndex=5 9 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 11 | 12 | # Direct log messages to stdout 13 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 14 | log4j.appender.stdout.Target=System.out 15 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.stdout.layout.ConversionPattern=%C %d{ABSOLUTE} %5p %c{1}:%L - %m%n 17 | -------------------------------------------------------------------------------- /http/README.md: -------------------------------------------------------------------------------- 1 | # Higgs WebSocket 2 | 3 | Containing project for the Higgs web socket modules 4 | -------------------------------------------------------------------------------- /http/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | http-client 4 | ${project.artifactId} 5 | Higgs HTTP Client 6 | jar 7 | 8 | io.higgs 9 | http 10 | ../pom.xml 11 | 0.0.25-SNAPSHOT 12 | 13 | 14 | 15 | 20 | 21 | 26 | 27 | 28 | 29 | 30 | org.codehaus.mojo 31 | exec-maven-plugin 32 | 33 | io.higgs.http.client.demo.Demo 34 | false 35 | 36 | 37 | java.util.logging.config.file 38 | logging.properties 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/ConnectHandler.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client; 2 | 3 | import io.higgs.core.ssl.SSLContextFactory; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.channel.SimpleChannelInboundHandler; 7 | import io.netty.handler.codec.http.HttpRequest; 8 | import io.netty.handler.codec.http.HttpResponse; 9 | import io.netty.handler.codec.http.LastHttpContent; 10 | 11 | /** 12 | * @author Courtney Robinson 13 | */ 14 | public class ConnectHandler extends SimpleChannelInboundHandler { 15 | protected final HttpRequest request; 16 | protected final boolean tunneling; 17 | protected final SimpleChannelInboundHandler handler; 18 | private final InitFactory factory; 19 | protected final SSLContextFactory sslCtx = new SSLContextFactory(); 20 | 21 | public ConnectHandler(boolean ssl, HttpRequest request, SimpleChannelInboundHandler handler, 22 | InitFactory factory) { 23 | this.tunneling = ssl; 24 | this.request = request; 25 | this.handler = handler; 26 | this.factory = factory; 27 | } 28 | 29 | protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { 30 | if (msg instanceof HttpResponse) { 31 | HttpResponse res = (HttpResponse) msg; 32 | //http://tools.ietf.org/html/rfc2817#section-5.2 33 | //rfc 2817 - 2xx status means we can proceed, the proxy has establish a connection 34 | int code = res.getStatus().code(); 35 | if (code > 199 && code < 300) { 36 | if (tunneling) { 37 | //add an SSL handler to the front of the pipeline 38 | sslCtx.addSSL(ctx.pipeline(), true, null); 39 | } 40 | } else { 41 | throw new ProxyConnectionException("Proxy server indicated it was unable to establish a secure " + 42 | "connection to the origin server", res); 43 | } 44 | } 45 | if (msg instanceof LastHttpContent) { 46 | //remove the connect handler so future responses go to the other handler 47 | ctx.pipeline().remove(this); 48 | ChannelPipeline pipeline = ctx.pipeline(); 49 | factory.newInstance(false, handler, null).configurePipeline(pipeline); 50 | writeOriginalRequest(ctx); 51 | } 52 | } 53 | 54 | protected void writeOriginalRequest(ChannelHandlerContext ctx) { 55 | //now write the original request 56 | ctx.channel().writeAndFlush(request); 57 | } 58 | 59 | public interface InitFactory { 60 | ClientIntializer newInstance(boolean ssl, SimpleChannelInboundHandler handler, ConnectHandler ch); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/FutureResponse.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client; 2 | 3 | import io.netty.channel.EventLoopGroup; 4 | import io.netty.util.concurrent.DefaultPromise; 5 | import io.netty.util.concurrent.Promise; 6 | 7 | /** 8 | * @author Courtney Robinson 9 | */ 10 | public class FutureResponse extends DefaultPromise { 11 | private final Response response; 12 | 13 | public FutureResponse(EventLoopGroup group, Response response) { 14 | super(group.next()); 15 | this.response = response; 16 | } 17 | 18 | @Override 19 | public Promise setFailure(Throwable cause) { 20 | Promise res = super.setFailure(cause); 21 | response.markFailed(cause); 22 | return res; 23 | } 24 | 25 | public Response getResponse() { 26 | return response; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/HttpFile.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client; 2 | 3 | import javax.activation.MimetypesFileTypeMap; 4 | import java.io.File; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author Courtney Robinson 10 | */ 11 | public class HttpFile { 12 | private final String name; 13 | private List files = new ArrayList<>(); 14 | private List contentTypes = new ArrayList<>(); 15 | private List texts = new ArrayList<>(); 16 | private MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap(); 17 | 18 | public HttpFile(String name, File file) { 19 | this(name); 20 | addFile(file); 21 | } 22 | 23 | public HttpFile(String name) { 24 | if (name == null) { 25 | throw new IllegalArgumentException("Cannot create an HttpFile with null as the name"); 26 | } 27 | this.name = name; 28 | } 29 | 30 | /** 31 | * Adds the given file to the set of files under this name. Assumed to be a none text file 32 | * 33 | * @param file the file to add 34 | * @return this 35 | */ 36 | public HttpFile addFile(File file) { 37 | return addFile(file, false); 38 | } 39 | 40 | /** 41 | * Adds the given file 42 | * 43 | * @param file the file to add 44 | * @param isText true if the file should be treated as a text file 45 | * @return this 46 | */ 47 | public HttpFile addFile(File file, boolean isText) { 48 | texts.add(texts.size(), isText); 49 | contentTypes.add(contentTypes.size(), mimeTypesMap.getContentType(file.getPath())); 50 | files.add(files.size(), file); 51 | return this; 52 | } 53 | 54 | public boolean isSingle() { 55 | return files.size() == 1; 56 | } 57 | 58 | public String name() { 59 | return name; 60 | } 61 | 62 | public File file() { 63 | return files.get(0); 64 | } 65 | 66 | public String contentType() { 67 | return contentTypes.get(0); 68 | } 69 | 70 | public boolean isText() { 71 | return texts.get(0); 72 | } 73 | 74 | public File[] fileSet() { 75 | return files.toArray(new File[files.size()]); 76 | } 77 | 78 | public String[] contentTypes() { 79 | return contentTypes.toArray(new String[contentTypes.size()]); 80 | } 81 | 82 | public boolean[] isTextSet() { 83 | boolean[] prim = new boolean[texts.size()]; 84 | for (int i = 0; i < texts.size(); i++) { 85 | boolean b = texts.get(i); 86 | prim[i] = b; 87 | } 88 | return prim; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/ProxyConnectionException.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client; 2 | 3 | import io.netty.handler.codec.http.HttpResponse; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class ProxyConnectionException extends RuntimeException { 9 | private final HttpResponse res; 10 | 11 | public ProxyConnectionException(String message, HttpResponse res) { 12 | super(message); 13 | this.res = res; 14 | } 15 | 16 | /** 17 | * @return The HTTP response returned by the proxy 18 | */ 19 | public HttpResponse getProxyResponse() { 20 | return res; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/ProxyDemo.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client; 2 | 3 | import io.higgs.core.func.Function2; 4 | import io.higgs.http.client.readers.PageReader; 5 | import io.netty.handler.codec.http.HttpHeaders; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.net.URI; 10 | 11 | /** 12 | * @author Courtney Robinson 13 | */ 14 | public final class ProxyDemo { 15 | private static HttpRequestBuilder defaults = new HttpRequestBuilder(); 16 | private static Logger log = LoggerFactory.getLogger(ProxyDemo.class); 17 | 18 | private ProxyDemo() { 19 | //configure default builder 20 | defaults.acceptedLanguages("en,fr") 21 | .acceptedMimeTypes("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") 22 | .charSet("ISO-8859-1,utf-8;q=0.7,*;q=0.7") 23 | .userAgent("Mozilla/5.0 (compatible; HiggsBoson/0.0.1; +https://github.com/zcourts/higgs)") 24 | .connection(HttpHeaders.Values.CLOSE) 25 | //automatically follow redirects when these status codes are returned 26 | .redirectOn(301, 302, 303, 307, 308); 27 | } 28 | 29 | public static void main(String[] args) throws Exception { 30 | HttpRequestBuilder proxied = defaults.copy(); 31 | proxied.proxy("localhost", 3128, "a", "b"); 32 | Request req = proxied.GET(new URI("http://api.datasift.com/v1/usage?username=zcourts&api_key=abc123"), 33 | new PageReader(new Function2() { 34 | public void apply(String s, final Response response) { 35 | System.out.println(s); 36 | } 37 | })); 38 | 39 | //this request will be tunneled because it uses HTTPS 40 | Request req2 = proxied.GET(new URI("https://api.datasift.com/v1/usage"), 41 | new PageReader(new Function2() { 42 | public void apply(String s, final Response response) { 43 | System.out.println(s); 44 | HttpRequestBuilder.shutdown(); 45 | } 46 | })); 47 | req.execute(); 48 | req2.execute(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/RequestTimeoutException.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Created by zcourts on 28/04/2016. 7 | */ 8 | public class RequestTimeoutException extends IOException { 9 | public RequestTimeoutException(String message) { 10 | super(message); 11 | } 12 | 13 | public static class ConnectTimeoutException extends RequestTimeoutException { 14 | public ConnectTimeoutException(String message) { 15 | super(message); 16 | } 17 | } 18 | 19 | public static class ResponseTimeoutException extends RequestTimeoutException { 20 | public ResponseTimeoutException(String message) { 21 | super(message); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/RetryPolicy.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public interface RetryPolicy { 7 | /** 8 | * Invoked when a request has failed, either because of a connection failure, the response was an error where 9 | * retries are allowed or another exception occurred. 10 | *

11 | * When the time comes, call the @{link #response.request().retry()} method... 12 | * 13 | * @param future This is the future returned to the user which is to be notified when an error occurs or a 14 | * response is successfully received. 15 | * @param cause if available, this will be the exception which caused the retry policy to be activated. 16 | * @param connectFailure if true, the connection failed to be established in the first place. 17 | * This is available to help distinguish between other types of errors so that a different 18 | * back off algorithm may be applied 19 | * @param response this is the response object that was present when the failure occurred. This will never 20 | * be null, but it's contents may be. i.e. there may not be a status, say, if connection 21 | * failed; or there may not be a body, if connection was successful but some error caused 22 | * prevent the body from being read 23 | */ 24 | void activate(FutureResponse future, Throwable cause, boolean connectFailure, Response response); 25 | } 26 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/readers/FileReader.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client.readers; 2 | 3 | import io.higgs.core.func.Function2; 4 | import io.higgs.http.client.Response; 5 | import io.netty.buffer.ByteBuf; 6 | 7 | import java.io.File; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.nio.file.Files; 11 | 12 | /** 13 | * @author Courtney Robinson 14 | */ 15 | public class FileReader extends Reader { 16 | protected File file; 17 | protected FileOutputStream out; 18 | 19 | public FileReader() throws IOException { 20 | this(null); 21 | } 22 | 23 | public FileReader(Function2 function) throws IOException { 24 | if (function != null) { 25 | listen(function); 26 | } 27 | file = Files.createTempFile("higgs-http-client-temp-" + new Double(Math.random()).longValue(), ".tmp").toFile(); 28 | out = new FileOutputStream(file); 29 | } 30 | 31 | @Override 32 | public void data(ByteBuf data) { 33 | byte[] tmp = new byte[data.readableBytes()]; 34 | data.readBytes(tmp); 35 | try { 36 | out.write(tmp); 37 | } catch (IOException e) { 38 | log.warn("Error writing data to file", e); 39 | } 40 | } 41 | 42 | @Override 43 | public void done() { 44 | try { 45 | out.close(); 46 | } catch (IOException e) { 47 | log.warn("Unable to close output stream of the downloaded file", e); 48 | } 49 | for (Function2 function : functions) { 50 | function.apply(file, response); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/readers/JsonStreamReader.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client.readers; 2 | 3 | import com.fasterxml.jackson.core.JsonFactory; 4 | import com.fasterxml.jackson.core.JsonParser; 5 | 6 | import java.io.IOException; 7 | 8 | /** 9 | * @author Courtney Robinson 10 | */ 11 | public class JsonStreamReader extends Reader { 12 | protected JsonFactory factory; 13 | protected JsonParser parser; 14 | 15 | public JsonStreamReader() { 16 | factory = new JsonFactory(); 17 | try { 18 | parser = factory.createParser(data); 19 | } catch (IOException e) { 20 | e.printStackTrace(); 21 | } 22 | // parser.read 23 | } 24 | 25 | @Override 26 | public void done() { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/readers/LineReader.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client.readers; 2 | 3 | import io.higgs.core.func.Function2; 4 | import io.higgs.http.client.Response; 5 | import io.netty.buffer.ByteBuf; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * Buffers a response stream in memory until an entire line is received. 11 | * Each subscribed callback is invoked once for every line received and 1 last time at the end of a stream 12 | * when the remaining contents may or may not have ended with a end of line delimiter 13 | *

14 | * This was created to support services that keep connections open and write line based data. 15 | * The Twitter streaming API for example... 16 | * 17 | * @author Courtney Robinson 18 | */ 19 | public class LineReader extends PageReader { 20 | public LineReader(Function2 function) { 21 | super(function); 22 | } 23 | 24 | public LineReader() { 25 | } 26 | 27 | //NOTE: we don't override done because it is required to be invoked once 28 | // everything is received to ensure entire content is read 29 | 30 | @Override 31 | public void data(ByteBuf content) { 32 | super.data(content); 33 | String line; 34 | try { 35 | while ((line = data.readLine()) != null) { 36 | writeLine(line); 37 | } 38 | buffer.discardReadBytes(); 39 | } catch (IOException e) { 40 | log.info(e.getMessage()); 41 | } 42 | } 43 | 44 | public void writeLine(String line) { 45 | for (Function2 function : functions) { 46 | function.apply(line, response); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /http/client/src/main/java/io/higgs/http/client/readers/PageReader.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client.readers; 2 | 3 | import io.higgs.core.func.Function2; 4 | import io.higgs.http.client.Response; 5 | 6 | /** 7 | * This collects a response stream in memory and then converts it to a string when the entire stream 8 | * is received. 9 | * 10 | * @author Courtney Robinson 11 | */ 12 | public class PageReader extends Reader { 13 | public PageReader(Function2 function) { 14 | super(function); 15 | } 16 | 17 | public PageReader() { 18 | } 19 | 20 | @Override 21 | public void done() { 22 | String str = buffer.toString(0, buffer.writerIndex(), utf8); 23 | for (Function2 function : functions) { 24 | function.apply(str, response); 25 | } 26 | //we read the entire stream 27 | buffer.readerIndex(buffer.writerIndex()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /http/client/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, file, stdout 3 | 4 | # Direct log messages to a log file 5 | log4j.appender.file=org.apache.log4j.RollingFileAppender 6 | log4j.appender.file.File=./var/log/higgs-http-client.log 7 | log4j.appender.file.MaxFileSize=100MB 8 | log4j.appender.file.MaxBackupIndex=1 9 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 11 | 12 | # Direct log messages to stdout 13 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 14 | log4j.appender.stdout.Target=System.out 15 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 16 | log4j.appender.stdout.layout.ConversionPattern=%C %d{ABSOLUTE} %5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /http/client/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # Default Logging Configuration File 3 | # 4 | # You can use a different file by specifying a filename 5 | # with the java.util.logging.config.file system property. 6 | # For example java -Djava.util.logging.config.file=myfile 7 | ############################################################ 8 | 9 | handlers= java.util.logging.ConsoleHandler 10 | 11 | # To also add the FileHandler, use the following line instead. 12 | #handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler 13 | 14 | # Default global logging level. 15 | # This specifies which kinds of events are logged across 16 | # all loggers. For any given facility this global level 17 | # can be overriden by a facility specific level 18 | # Note that the ConsoleHandler also has a separate level 19 | # setting to limit messages printed to the console. 20 | .level= INFO 21 | 22 | ############################################################ 23 | # Handler specific properties. 24 | # Describes specific configuration info for Handlers. 25 | ############################################################ 26 | 27 | # default file output is in user's home directory. 28 | java.util.logging.FileHandler.pattern = %h/java%u.log 29 | java.util.logging.FileHandler.limit = 50000 30 | java.util.logging.FileHandler.count = 1 31 | java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter 32 | 33 | # Limit the message that are printed on the console to INFO and above. 34 | java.util.logging.ConsoleHandler.level = INFO 35 | java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter 36 | 37 | # Example to customize the SimpleFormatter output format 38 | # to print one-line log message like this: 39 | # : [] 40 | # 41 | # java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n 42 | 43 | ############################################################ 44 | # Facility specific properties. 45 | # Provides extra control for each logger. 46 | ############################################################ 47 | 48 | # For example, set the com.xyz.foo logger to only log SEVERE 49 | # messages: 50 | com.xyz.foo.level = SEVERE 51 | 52 | sun.net.www.protocol.http.HttpURLConnection.level = ALL 53 | -------------------------------------------------------------------------------- /http/client/src/test/java/io/higgs/http/client/JSONRequestTest.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.client; 2 | 3 | 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import io.higgs.core.func.Function2; 6 | import io.higgs.http.client.readers.PageReader; 7 | import org.junit.Test; 8 | 9 | import java.net.URI; 10 | import java.net.URISyntaxException; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | public class JSONRequestTest { 15 | URI uri; 16 | PageReader reader = new PageReader(new Function2() { 17 | @Override 18 | public void apply(String s, Response response) { 19 | } 20 | }); 21 | Map map = new HashMap(); 22 | 23 | public JSONRequestTest() throws URISyntaxException { 24 | uri = new URI("http://httpbin.org"); 25 | } 26 | 27 | @Test 28 | public void setContentUsingSetDataStr() { 29 | HttpRequestBuilder.instance().postJSON(uri, reader) 30 | .setData("{}"); 31 | } 32 | 33 | @Test 34 | public void setContentUsingSetDataObj() throws JsonProcessingException { 35 | HttpRequestBuilder.instance().postJSON(uri, reader) 36 | .setData(map); 37 | } 38 | 39 | @Test(expected = IllegalStateException.class) 40 | public void throwIllegalStateIfAddFieldCalledAfterSetDataStr() throws JsonProcessingException { 41 | HttpRequestBuilder.instance().postJSON(uri, reader) 42 | .setData(map) 43 | //can't combine setData with addField 44 | .addField("a", "b"); 45 | } 46 | 47 | @Test(expected = IllegalStateException.class) 48 | public void throwIllegalStateIfAddFieldCalledAfterSetDataObj() throws JsonProcessingException { 49 | HttpRequestBuilder.instance().postJSON(uri, reader) 50 | .setData("{}") 51 | //can't combine setData with addField 52 | .addField("a", "b"); 53 | } 54 | 55 | @Test(expected = IllegalStateException.class) 56 | public void throwIllegalStateIfAddFieldCalledBeforeSetDataStr() throws JsonProcessingException { 57 | HttpRequestBuilder.instance().postJSON(uri, reader) 58 | .addField("a", "b") 59 | //can't combine setData with addField 60 | .setData(map); 61 | } 62 | 63 | @Test(expected = IllegalStateException.class) 64 | public void throwIllegalStateIfAddFieldCalledBeforeSetDataObj() throws JsonProcessingException { 65 | HttpRequestBuilder.instance().postJSON(uri, reader) 66 | .addField("a", "b") 67 | //can't combine setData with addField 68 | .setData("{}"); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /http/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | ${project.artifactId} 4 | http 5 | pom 6 | Higgs' HTTP server and client implementation 7 | 8 | 9 | io.higgs 10 | higgs 11 | ../pom.xml 12 | 0.0.25-SNAPSHOT 13 | 14 | 15 | server 16 | client 17 | 18 | 19 | 20 | 21 | io.higgs 22 | core 23 | ${project.version} 24 | 25 | 26 | 27 | 28 | 29 | io.higgs 30 | core 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /http/server/README.md: -------------------------------------------------------------------------------- 1 | # HTTP S3 (Single Site Server) 2 | 3 | A parent project for a group of modules that provide the ability to build REST services or full websites using 4 | any template language available on the JVM (if the API is implemented, see thymeleaf and mustache). 5 | -------------------------------------------------------------------------------- /http/server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | http-server 4 | ${project.artifactId} 5 | Higgs HTTP S3 (Single Site Server) 6 | pom 7 | 8 | io.higgs 9 | http 10 | ../pom.xml 11 | 0.0.25-SNAPSHOT 12 | 13 | 14 | s3 15 | transformer-defaults 16 | transformer-thymeleaf 17 | transformer-mustache 18 | transformer-handlebars 19 | 20 | 21 | 22 | 23 | io.higgs 24 | http-s3 25 | ${project.version} 26 | 27 | 28 | 29 | 30 | 31 | joda-time 32 | joda-time 33 | 2.1 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /http/server/s3/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | http-s3 4 | ${project.artifactId} 5 | 6 | Higgs HTTP S3 (Single Site Server). This is the core module with the server implementation. 7 | The other modules within this parent are extensions to this module that adds functionality to the server. 8 | 9 | jar 10 | 11 | io.higgs 12 | http-server 13 | ../pom.xml 14 | 0.0.25-SNAPSHOT 15 | 16 | 17 | 18 | org.apache.shiro 19 | shiro-core 20 | 1.2.3 21 | 22 | 23 | org.slf4j 24 | slf4j-api 25 | 26 | 27 | 28 | 29 | 30 | commons-logging 31 | commons-logging 32 | 1.1.1 33 | 34 | 35 | org.kohsuke.metainf-services 36 | metainf-services 37 | 1.1 38 | true 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/HttpRequestDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package io.higgs.http.server; 17 | 18 | import io.higgs.http.server.protocol.HttpProtocolConfiguration; 19 | import io.netty.handler.codec.http.HttpMessage; 20 | import io.netty.handler.codec.http.HttpMethod; 21 | import io.netty.handler.codec.http.HttpVersion; 22 | 23 | public class HttpRequestDecoder extends io.netty.handler.codec.http.HttpRequestDecoder { 24 | protected final HttpProtocolConfiguration config; 25 | 26 | public HttpRequestDecoder(HttpProtocolConfiguration config) { 27 | this.config = config; 28 | } 29 | 30 | @Override 31 | protected HttpMessage createMessage(String[] initialLine) throws Exception { 32 | return new HttpRequest(HttpVersion.valueOf(initialLine[2]) 33 | , HttpMethod.valueOf(initialLine[0]) 34 | , initialLine[1] 35 | , config); 36 | } 37 | 38 | @Override 39 | protected HttpMessage createInvalidMessage() { 40 | return new HttpRequest(HttpVersion.HTTP_1_0, HttpMethod.GET, "/bad-request", config); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/HttpResponseEncoder.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class HttpResponseEncoder extends io.netty.handler.codec.http.HttpResponseEncoder { 7 | } 8 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/HttpStatus.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server; 2 | 3 | import io.netty.handler.codec.http.HttpResponseStatus; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class HttpStatus extends HttpResponseStatus { 9 | /** 10 | * Creates a new instance with the specified {@code code} and its 11 | * {@code reasonPhrase}. 12 | */ 13 | public HttpStatus(int code, String reasonPhrase) { 14 | super(code, reasonPhrase); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/HttpTemplate.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class HttpTemplate { 7 | private String name, path; 8 | private int code; 9 | 10 | /** 11 | * @return the name of the template file. e.g. 404.html 12 | */ 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | public void setName(String name) { 18 | this.name = name; 19 | } 20 | 21 | /** 22 | * @return the URI used to match this template e.g. /404-not-found 23 | * if this a path is not set then the {@link #getCode()} is returned. 24 | * If this is not an error template then {@link #getCode()} is always 0 25 | */ 26 | public String getPath() { 27 | return path == null ? String.valueOf(getCode()) : path; 28 | } 29 | 30 | public void setPath(String path) { 31 | this.path = path; 32 | } 33 | 34 | public int getCode() { 35 | return code; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/ManagedWriter.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server; 2 | 3 | import io.higgs.core.ResolvedFile; 4 | import io.netty.channel.ChannelFuture; 5 | 6 | /** 7 | * @author Courtney Robinson 8 | */ 9 | public interface ManagedWriter { 10 | ChannelFuture doWrite(); 11 | 12 | boolean isDone(); 13 | 14 | ResolvedFile getFile(); 15 | } 16 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/MessagePusher.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server; 2 | 3 | import io.netty.channel.ChannelFuture; 4 | import io.netty.channel.ChannelHandlerContext; 5 | 6 | /** 7 | * A response pusher is a generic interface used by HTTP and WebSockets to write responses back to the browser. 8 | * This interface allows support for PUSH technologies and WebSockets to work seamlessly by using the same interface. 9 | * 10 | * @author Courtney Robinson 11 | */ 12 | public interface MessagePusher { 13 | 14 | /** 15 | * Push a message up to the client. If the underlying connection is a web socket then 16 | * a new websocket frame is written, if it is a persistent HTTP request the message is written 17 | * as additional data to anything previously sent. 18 | * 19 | * @param message the message to push to the client 20 | * @return a future which is notified when the message is successfully sent, cancelled or otherwise interrupted 21 | * due to failure. This includes if the underlying connection has been closed. 22 | */ 23 | ChannelFuture push(Object message); 24 | 25 | /** 26 | * @return The underlying context which supports this pusher 27 | */ 28 | ChannelHandlerContext ctx(); 29 | } 30 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/ParamInjector.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server; 2 | 3 | import io.higgs.http.server.protocol.HttpMethod; 4 | import io.netty.channel.ChannelHandlerContext; 5 | 6 | /** 7 | * @author Courtney Robinson 8 | */ 9 | public interface ParamInjector { 10 | Object[] injectParams(HttpMethod method, HttpRequest request, HttpResponse res, ChannelHandlerContext ctx, Object 11 | [] params); 12 | } 13 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/Transcriber.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server; 2 | 3 | import java.util.Comparator; 4 | import java.util.Set; 5 | import java.util.TreeSet; 6 | 7 | /** 8 | * Essentially a request re-writer 9 | * On receiving a request it modifies the request path based on the rules given 10 | * 11 | * @author Courtney Robinson 12 | */ 13 | public class Transcriber { 14 | //sort transcriptions by creation time ensuring FIFO 15 | Set transcriptions = new TreeSet<>(new Comparator() { 16 | public int compare(final Transcription o1, final Transcription o2) { 17 | if (o1.getCreatedAt() < o2.getCreatedAt()) { 18 | return -1; 19 | } 20 | if (o1.getCreatedAt() > o2.getCreatedAt()) { 21 | return 1; 22 | } 23 | return 0; 24 | } 25 | }); 26 | 27 | public void transcribe(HttpRequest request) { 28 | //apply any transcription 29 | for (Transcription transcription : transcriptions) { 30 | if (transcription.matches(request.getUri())) { 31 | if (transcription.isReplaceWholeRequest()) { 32 | request.setUri(transcription.getReplacementPath()); 33 | } else { 34 | String newPath; 35 | if (transcription.isReplaceFirstOccurrence()) { 36 | newPath = transcription.replaceFirstMatch(request.getUri()); 37 | } else { 38 | newPath = transcription.replaceAllMatches(request.getUri()); 39 | } 40 | request.setUri(newPath); 41 | } 42 | break; 43 | } 44 | } 45 | } 46 | 47 | /** 48 | * Adds a transcription to be applied to matching requests 49 | * 50 | * @param transcription 51 | */ 52 | public void addTranscription(Transcription transcription) { 53 | transcriptions.add(transcription); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/WrappedResponse.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class WrappedResponse { 7 | private final String callback; 8 | private final Object data; 9 | 10 | public WrappedResponse(Object data) { 11 | this(null, data); 12 | } 13 | 14 | public WrappedResponse(String callback, Object data) { 15 | this.callback = callback; 16 | this.data = data; 17 | } 18 | 19 | public String callback() { 20 | return callback; 21 | } 22 | 23 | public Object data() { 24 | return data; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return "WrappedResponse{" + 30 | "callback='" + callback + '\'' + 31 | ", data=" + data + 32 | '}'; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/auth/DefaultHiggsSessionDAO.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.auth; 2 | 3 | import org.apache.shiro.session.Session; 4 | import org.apache.shiro.session.UnknownSessionException; 5 | import org.apache.shiro.session.mgt.eis.MemorySessionDAO; 6 | import org.apache.shiro.session.mgt.eis.SessionDAO; 7 | 8 | import java.io.Serializable; 9 | import java.util.Collection; 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | 13 | /** 14 | * @author Courtney Robinson 15 | */ 16 | public class DefaultHiggsSessionDAO extends MemorySessionDAO implements SessionDAO { 17 | protected Map sessions = new ConcurrentHashMap<>(); 18 | 19 | public DefaultHiggsSessionDAO(String sessionDirName) { 20 | } 21 | 22 | @Override 23 | public Serializable create(Session session) { 24 | createOrUpdateSession(session); 25 | return session.getId(); 26 | } 27 | 28 | private boolean createOrUpdateSession(Session session) { 29 | sessions.put(session.getId(), session); 30 | return false; 31 | } 32 | 33 | @Override 34 | public Session readSession(Serializable sessionId) throws UnknownSessionException { 35 | Session session = sessions.get(sessionId); 36 | if (session == null || session.getId() == null || session.getId().toString().isEmpty()) { 37 | throw new UnknownSessionException(); 38 | } 39 | return session; 40 | } 41 | 42 | @Override 43 | public void update(Session session) throws UnknownSessionException { 44 | createOrUpdateSession(session); 45 | } 46 | 47 | @Override 48 | public void delete(Session session) { 49 | sessions.remove(session.getId()); 50 | } 51 | 52 | @Override 53 | public Collection getActiveSessions() { 54 | return sessions.values(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/auth/FlashValue.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.auth; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class FlashValue implements Serializable { 9 | 10 | private final Object value; 11 | 12 | public FlashValue(Object value) { 13 | this.value = value; 14 | } 15 | 16 | public Object getValue() { 17 | return value; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/auth/HiggsSessionFactory.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.auth; 2 | 3 | import org.apache.shiro.session.Session; 4 | import org.apache.shiro.session.mgt.SessionContext; 5 | import org.apache.shiro.session.mgt.SessionFactory; 6 | import org.apache.shiro.session.mgt.SimpleSessionFactory; 7 | 8 | /** 9 | * @author Courtney Robinson 10 | */ 11 | public class HiggsSessionFactory extends SimpleSessionFactory implements SessionFactory { 12 | public Session createSession(SessionContext initData) { 13 | if (initData.getSessionId() != null) { 14 | return new HiggsSession(initData.getSessionId()); 15 | } 16 | return super.createSession(initData); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/auth/HiggsSessionManager.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.auth; 2 | 3 | import org.apache.shiro.session.mgt.DefaultSessionManager; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class HiggsSessionManager extends DefaultSessionManager { 9 | } 10 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/auth/InvalidSessionDirectory.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.auth; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class InvalidSessionDirectory extends RuntimeException { 9 | public InvalidSessionDirectory(String msg, IOException e) { 10 | super(msg, e); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/config/HttpConfig.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.config; 2 | 3 | import io.higgs.core.ServerConfig; 4 | import io.higgs.http.server.protocol.HttpMethod; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public class HttpConfig extends ServerConfig { 10 | public boolean add_form_url_decoder = true; 11 | public boolean add_json_decoder = true; 12 | public boolean enable_keep_alive_requests; 13 | public String index_file = "index.html"; 14 | public boolean serve_index_file = true; 15 | public boolean enable_directory_listing = true; 16 | public String public_directory = "public"; 17 | public String security_config_path = "classpath:shiro.ini"; 18 | // 19 | private Map errors = new HashMap<>(); 20 | 21 | public HttpConfig() { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/errors/HttpError.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.errors; 2 | 3 | import javax.ws.rs.Path; 4 | 5 | public class HttpError { 6 | @Path("404") 7 | public String notFound() { 8 | return "

Not Found

"; 9 | } 10 | 11 | public static class HttpErrorCode { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/jaxrs/SimpleRuntimeDelegate.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.jaxrs; 2 | 3 | import org.kohsuke.MetaInfServices; 4 | 5 | import javax.ws.rs.core.Application; 6 | import javax.ws.rs.core.Link; 7 | import javax.ws.rs.core.Response; 8 | import javax.ws.rs.core.UriBuilder; 9 | import javax.ws.rs.core.Variant; 10 | import javax.ws.rs.ext.RuntimeDelegate; 11 | 12 | /** 13 | * @author Courtney Robinson 14 | */ 15 | @MetaInfServices(RuntimeDelegate.class) 16 | public class SimpleRuntimeDelegate extends RuntimeDelegate { 17 | @Override 18 | public UriBuilder createUriBuilder() { 19 | throw new UnsupportedOperationException(); 20 | } 21 | 22 | @Override 23 | public Response.ResponseBuilder createResponseBuilder() { 24 | return new ResponseBuilder(); 25 | } 26 | 27 | @Override 28 | public Variant.VariantListBuilder createVariantListBuilder() { 29 | throw new UnsupportedOperationException(); 30 | } 31 | 32 | @Override 33 | public T createEndpoint(Application application, Class endpointType) throws IllegalArgumentException, 34 | UnsupportedOperationException { 35 | throw new UnsupportedOperationException(); 36 | } 37 | 38 | @Override 39 | public HeaderDelegate createHeaderDelegate(Class type) throws IllegalArgumentException { 40 | throw new UnsupportedOperationException(); 41 | } 42 | 43 | @Override 44 | public Link.Builder createLinkBuilder() { 45 | throw new UnsupportedOperationException(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/DefaultValidator.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import io.higgs.http.server.MethodParam; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class DefaultValidator implements Validator { 9 | @Override 10 | public boolean isValid(Object value) { 11 | //value must not be null, and if value is a string it cannot be empty 12 | return value != null && (!(value instanceof String) || !((String) value).isEmpty()); 13 | } 14 | 15 | @Override 16 | public String getValidationMessage(MethodParam param) { 17 | return String.format("%s is required", param.getName()); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/FormFiles.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class FormFiles extends HashMap { 9 | public int getSize() { 10 | return size(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/FormParams.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class FormParams extends HashMap { 9 | public int getSize() { 10 | return size(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/HttpCookie.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import io.higgs.core.reflect.ReflectionUtil; 4 | import io.netty.handler.codec.http.Cookie; 5 | import io.netty.handler.codec.http.DefaultCookie; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.lang.reflect.Field; 10 | import java.lang.reflect.Modifier; 11 | import java.util.HashSet; 12 | import java.util.Set; 13 | 14 | /** 15 | * @author Courtney Robinson 16 | */ 17 | public class HttpCookie extends DefaultCookie { 18 | protected Logger log = LoggerFactory.getLogger(getClass()); 19 | 20 | public HttpCookie(Cookie cookie) { 21 | this(cookie.getName(), cookie.getValue()); 22 | Set fields = ReflectionUtil.getAllFields(new HashSet(), DefaultCookie.class, 1); 23 | for (Field field : fields) { 24 | try { 25 | if (!Modifier.isFinal(field.getModifiers())) { 26 | field.setAccessible(true); 27 | field.set(this, field.get(cookie)); 28 | } 29 | } catch (Throwable t) { 30 | log.warn("Error copying cookie field", t); 31 | } 32 | } 33 | } 34 | 35 | public HttpCookie(String name, String value) { 36 | super(name, value); 37 | setPath("/"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/HttpCookies.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class HttpCookies extends HashMap { 9 | public String getValue(String name) { 10 | HttpCookie cookie = get((Object) name); 11 | if (cookie != null) { 12 | return cookie.getValue(); 13 | } 14 | return null; 15 | } 16 | 17 | public int getSize() { 18 | return size(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/HttpFile.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import io.netty.handler.codec.http.multipart.FileUpload; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | 8 | /** 9 | * @author Courtney Robinson 10 | */ 11 | public class HttpFile { 12 | private String parameterName; 13 | private String fileName; 14 | private String contentType; 15 | private boolean inMemory; 16 | private File file; 17 | 18 | public HttpFile(final FileUpload data) { 19 | parameterName = data.getName(); 20 | fileName = data.getFilename(); 21 | contentType = data.getContentType(); 22 | inMemory = data.isInMemory(); 23 | try { 24 | file = data.getFile(); 25 | } catch (IOException e) { 26 | //not possible 27 | } 28 | } 29 | 30 | public boolean isInMemory() { 31 | return inMemory; 32 | } 33 | 34 | public File getFile() { 35 | return file; 36 | } 37 | 38 | /** 39 | * Get the parameter name used to represent the file in the HTML form 40 | * 41 | * @return 42 | */ 43 | public String getParameterName() { 44 | return parameterName; 45 | } 46 | 47 | /** 48 | * Returns the content type passed by the browser or null if not defined. 49 | * 50 | * @return the content type passed by the browser or null if not defined. 51 | */ 52 | public String getContentType() { 53 | return contentType; 54 | } 55 | 56 | /** 57 | * Returns the original filename in the client's filesystem, as provided by the browser 58 | * (or other client software). 59 | * 60 | * @return the original filename 61 | */ 62 | public String getFileName() { 63 | return fileName; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/IllegalValidatorException.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class IllegalValidatorException extends RuntimeException { 7 | public IllegalValidatorException(String s, Throwable e) { 8 | super(s, e); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/QueryParams.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | 6 | /** 7 | * Represents the set of query string parameters available with a request 8 | * 9 | * @author Courtney Robinson 10 | */ 11 | public class QueryParams extends HashMap> { 12 | /** 13 | * Gets the first value of the query string parameter with the given name 14 | * 15 | * @param name the name of the query string parameter to get 16 | * @return the value of the parameter or null if it doesn't exist 17 | */ 18 | public String getFirst(String name) { 19 | List vals = get(name); 20 | if (vals == null) { 21 | return null; 22 | } 23 | return vals.get(0); 24 | } 25 | 26 | public int getSize() { 27 | return size(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/RequiredParam.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | /** 4 | * A required parameter is any injectable parameter which must pass some validation test in order to be considered valid 5 | * The validation test is specified by {@link valid}. If no validation test is provided the parameter will be marked 6 | * as valid ONLY IF it is not null and if it is a string it must not be empty. Those are the two default validations 7 | * done anything else must be done with a custom {@link Validator} 8 | * 9 | * @author Courtney Robinson 10 | */ 11 | public class RequiredParam { 12 | protected T value; 13 | protected boolean valid; 14 | 15 | public RequiredParam(T value, boolean valid) { 16 | this.value = value; 17 | this.valid = valid; 18 | } 19 | 20 | public T getValue() { 21 | return value; 22 | } 23 | 24 | public boolean isValid() { 25 | return valid; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return "RequiredParam{" + 31 | "valid=" + valid + 32 | ", value=" + value + 33 | '}'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/SessionParam.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author Courtney Robinson 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ ElementType.PARAMETER }) 13 | public @interface SessionParam { 14 | String value(); 15 | } 16 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/ValidationResult.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class ValidationResult extends HashMap { 9 | private boolean valid = true; 10 | 11 | /** 12 | * Mark this validation as invalid 13 | */ 14 | public void invalid() { 15 | this.valid = false; 16 | } 17 | 18 | /** 19 | * @return true if no validation failed 20 | */ 21 | public boolean isValid() { 22 | return valid; 23 | } 24 | 25 | public void setValid(boolean valid) { 26 | this.valid = valid; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "ValidationResult{" + 32 | "valid=" + valid + 33 | '}'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/Validator.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import io.higgs.http.server.MethodParam; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public interface Validator { 9 | boolean isValid(Object value); 10 | 11 | String getValidationMessage(MethodParam param); 12 | } 13 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/params/valid.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.params; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author Courtney Robinson 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ ElementType.PARAMETER }) 13 | public @interface valid { 14 | Class value() default DefaultValidator.class; 15 | } 16 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/protocol/HttpDetector.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.protocol; 2 | 3 | import io.higgs.core.ProtocolDetector; 4 | import io.higgs.http.server.HttpRequestDecoder; 5 | import io.higgs.http.server.HttpResponseEncoder; 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.ChannelPipeline; 9 | import io.netty.handler.stream.ChunkedWriteHandler; 10 | 11 | /** 12 | * @author Courtney Robinson 13 | */ 14 | public class HttpDetector implements ProtocolDetector { 15 | protected final HttpProtocolConfiguration config; 16 | 17 | public HttpDetector(HttpProtocolConfiguration config) { 18 | this.config = config; 19 | } 20 | 21 | @Override 22 | public boolean detected(ChannelHandlerContext ctx, ByteBuf in) { 23 | final int magic1 = in.getUnsignedByte(in.readerIndex()); 24 | final int magic2 = in.getUnsignedByte(in.readerIndex() + 1); 25 | return 26 | magic1 == 'G' && magic2 == 'E' || // GET 27 | magic1 == 'P' && magic2 == 'O' || // POST 28 | magic1 == 'P' && magic2 == 'U' || // PUT 29 | magic1 == 'H' && magic2 == 'E' || // HEAD 30 | magic1 == 'O' && magic2 == 'P' || // OPTIONS 31 | magic1 == 'P' && magic2 == 'A' || // PATCH 32 | magic1 == 'D' && magic2 == 'E' || // DELETE 33 | magic1 == 'T' && magic2 == 'R' || // TRACE 34 | magic1 == 'C' && magic2 == 'O'; // CONNECT 35 | } 36 | 37 | @Override 38 | public HttpHandler setupPipeline(ChannelPipeline p, ChannelHandlerContext ctx) { 39 | //HttpHandler is stateful so must do an instance per request/channel 40 | HttpHandler h = new HttpHandler(config); 41 | p.addLast("decoder", new HttpRequestDecoder(config)); 42 | p.addLast("encoder", new HttpResponseEncoder()); 43 | p.addLast("chunkedWriter", new ChunkedWriteHandler()); 44 | //ByteBufToHttpContent must come before compressor and after chunked writer to support 45 | //compressing chunked files 46 | // p.addLast("ByteBufToHttpContent", new MessageToMessageEncoder() { 47 | // @Override 48 | // protected void encode(ChannelHandlerContext ctx, ByteBuf msg, MessageBuf out) throws Exception { 49 | // out.add(new DefaultHttpContent(msg.retain())); 50 | // } 51 | // }); 52 | // p.addLast("deflater", new HttpContentCompressor()); 53 | p.addLast("handler", h); 54 | return h; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/protocol/HttpDetectorFactory.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.protocol; 2 | 3 | import io.higgs.core.ProtocolDetector; 4 | import io.higgs.core.ProtocolDetectorFactory; 5 | 6 | /** 7 | * @author Courtney Robinson 8 | */ 9 | public class HttpDetectorFactory implements ProtocolDetectorFactory { 10 | private final HttpProtocolConfiguration config; 11 | protected int priority; 12 | 13 | public HttpDetectorFactory(HttpProtocolConfiguration config) { 14 | this.config = config; 15 | } 16 | 17 | @Override 18 | public ProtocolDetector newProtocolDetector() { 19 | return new HttpDetector(config); 20 | } 21 | 22 | @Override 23 | public int setPriority(int value) { 24 | int old = priority; 25 | priority = value; 26 | return old; 27 | } 28 | 29 | @Override 30 | public int priority() { 31 | return priority; 32 | } 33 | 34 | @Override 35 | public int compareTo(ProtocolDetectorFactory that) { 36 | return that.priority() - this.priority(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/protocol/MediaTypeDecoder.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.protocol; 2 | 3 | import io.higgs.core.reflect.dependency.DependencyProvider; 4 | import io.higgs.http.server.resource.MediaType; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.handler.codec.http.HttpContent; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author Courtney Robinson 12 | */ 13 | public interface MediaTypeDecoder { 14 | /** 15 | * @param mediaType the media type to check compatibility for 16 | * @return true if this decoder can handle the given media type 17 | */ 18 | boolean canDecode(List mediaType); 19 | 20 | /** 21 | * Called each time a chunk of data is received for the request 22 | * 23 | * @param chunk the chunk to decode or buffer 24 | */ 25 | void offer(HttpContent chunk); 26 | 27 | /** 28 | * Invoked when all the HTTP content for the request has een received. {@link #offer(HttpContent)} will not be 29 | * called after this and whatever is decoded will be passed to the target method 30 | * 31 | * @param ctx the context 32 | */ 33 | void finished(ChannelHandlerContext ctx); 34 | 35 | /** 36 | * @return A dependency provider which the decoder can use to provide anything that can be injected into methods 37 | */ 38 | DependencyProvider provider(); 39 | } 40 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/resource/JsonData.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.resource; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class JsonData { 9 | protected final JsonNode node; 10 | protected final String json; 11 | 12 | public JsonData(String json, JsonNode node) { 13 | this.json = json; 14 | this.node = node; 15 | } 16 | 17 | public JsonNode getNode() { 18 | return node; 19 | } 20 | 21 | public String getJson() { 22 | return json; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return json; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /http/server/s3/src/main/java/io/higgs/http/server/transformers/ResponseTransformer.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.transformers; 2 | 3 | import io.higgs.core.Sortable; 4 | import io.higgs.http.server.HttpRequest; 5 | import io.higgs.http.server.HttpResponse; 6 | import io.higgs.http.server.protocol.HttpMethod; 7 | import io.higgs.http.server.resource.MediaType; 8 | import io.netty.channel.ChannelHandlerContext; 9 | 10 | /** 11 | * The server uses a {@link java.util.TreeSet} of transformers. The first transformer returned is of the highest 12 | * priority according to the sorted set. That transformer can decide to try using another 13 | * transformer but the server will always use the first one returned by the queue (which is the last one added...). 14 | * 15 | * @author Courtney Robinson 16 | */ 17 | public interface ResponseTransformer extends Sortable { 18 | /** 19 | * Determines if, given the response object and the media types accepted by the client this 20 | * transformer can convert the response object into one of the accepted types 21 | * 22 | * @param response the response object that would need to be transformed 23 | * @param request the request which generated the response 24 | * @param mediaType The media type which matched in the {@link HttpMethod}'s produces AND in the client 25 | * set of accepted media types. 26 | * @return true if this transformer can convert the response to one of the supported media types... 27 | */ 28 | boolean canTransform(Object response, HttpRequest request, MediaType mediaType, 29 | HttpMethod method, ChannelHandlerContext ctx); 30 | 31 | /** 32 | * Given the response object transform it into one of the accepted media types 33 | * 34 | * @param response the response object to be transformed 35 | * @param request the request which generated the response 36 | * @param httpResponse the HTTP response which will be returned to the client 37 | * @param method The method which was invoked to produce the response 38 | * @param ctx the channel context, provided in the case where an unrecoverable error is 39 | * encountered an error response can be returned by by passing the normal response 40 | * route @return an HTTP response. If null is returned the server will return 41 | * 406 Not Acceptable to the client... 42 | * (i.e. The requested resource is only capable of generating content not acceptable 43 | * according to the Accept headers sent in the request.) 44 | */ 45 | void transform(Object response, HttpRequest request, HttpResponse httpResponse, MediaType mediaType, 46 | HttpMethod method, 47 | ChannelHandlerContext ctx); 48 | 49 | /** 50 | * @return If a transformer maintains state then this method should return a new instance every time. 51 | * If not then this should be returned. 52 | */ 53 | ResponseTransformer instance(); 54 | } 55 | -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | #if true a new instance of a resource is created per request otherwise, one instance serves all requests 2 | instance_per_request : true 3 | port : 3434 4 | log_requests : true 5 | #directory where sessions are persisted on disk 6 | session_dir : /tmp/hs3-sessions/ 7 | session_path : / 8 | #ignored if null 9 | session_domain: 10 | #7 days in milliseconds 11 | session_max_age : 604800000 12 | session_http_only: false 13 | #ignored if null 14 | session_ports: 15 | #default error template used when no template is found for the specific error message 16 | default_error_template : error/default 17 | #add the default injector used to inject parameters into resource methods 18 | add_default_injector : true 19 | #if true static files will be served from template_config. 20 | add_static_resource_filter : true 21 | #path to the directory from which static files will be served (relative or absolute) 22 | #bare in mind if you want to serve files from the classpath a relative path is probably best 23 | #if the path is relative (doesn't start with /) then a / is automatically prepended before 24 | #checking on disk so "public" becomes "/public" 25 | public_directory : public 26 | #if true directories in public_directory will list the files in them 27 | enable_directory_listing : true 28 | #if true when its a directory, index_file will be sent automatically if set... 29 | serve_index_file : true 30 | #the name of the default file to serve from directories 31 | index_file : index.html 32 | -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | #reduce the thymeleaf logging to warnings or above 2 | log4j.logger.org.thymeleaf = WARN 3 | # Root logger option 4 | log4j.rootLogger=INFO, file, stdout 5 | 6 | # Direct log messages to a log file 7 | log4j.appender.file=org.apache.log4j.RollingFileAppender 8 | log4j.appender.file.File=./var/log/hs3.log 9 | log4j.appender.file.MaxFileSize=100MB 10 | log4j.appender.file.MaxBackupIndex=5 11 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 12 | log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 13 | 14 | # Direct log messages to stdout 15 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 16 | log4j.appender.stdout.Target=System.out 17 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 18 | log4j.appender.stdout.layout.ConversionPattern=%C %d{ABSOLUTE} %5p %c{1}:%L - %m%n 19 | 20 | #make request_logger output format different from normal logs 21 | log4j.logger.request_logger=DEBUG, request_logger_console,request_logger_file 22 | #prevent request logs from propagating to the root logger 23 | log4j.additivity.request_logger=false 24 | 25 | log4j.appender.request_logger_console=org.apache.log4j.ConsoleAppender 26 | log4j.appender.request_logger_console.layout=org.apache.log4j.PatternLayout 27 | log4j.appender.request_logger_console.layout.ConversionPattern=%m%n 28 | 29 | log4j.appender.request_logger_file=org.apache.log4j.RollingFileAppender 30 | log4j.appender.request_logger_file.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.request_logger_file.layout.ConversionPattern=%m%n 32 | 33 | log4j.appender.request_logger_file.File=./var/log/hs3-requests.log 34 | log4j.appender.request_logger_file.MaxFileSize=100MB 35 | log4j.appender.request_logger_file.MaxBackupIndex=5 -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/public/default.html: -------------------------------------------------------------------------------- 1 |

Default file

-------------------------------------------------------------------------------- /http/server/s3/src/main/resources/public/demo.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | Static file demo -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zcourts/higgs/504504331ded8f276fc7862986747fdeff132d90/http/server/s3/src/main/resources/public/favicon.ico -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/public/header.html: -------------------------------------------------------------------------------- 1 | HTML header to be included in other templates. -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/public/index.html: -------------------------------------------------------------------------------- 1 |

Some random index file

-------------------------------------------------------------------------------- /http/server/s3/src/main/resources/public/sub/defaultt.html: -------------------------------------------------------------------------------- 1 |

Index in sub directory

-------------------------------------------------------------------------------- /http/server/s3/src/main/resources/public/sub/random.html: -------------------------------------------------------------------------------- 1 | Just random -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/shiro.ini: -------------------------------------------------------------------------------- 1 | [main] 2 | # set default session timeout to 1 day 3 | securityManager.sessionManager.globalSessionTimeout = 86400000 4 | -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/templates/api.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
Default template variable nameSize
${_query.size}${_query.size}
${_form.size}${_form.size}
${_files.size}${_files.size}
${_session}${_session.size}
${_cookies.size}${_cookies.size}
${_response}${_response}
34 | 35 |

Welcome to the Higgs Thymeleaf demo!

36 | 37 |
38 |

39 | Type some text (if you like):

40 | 41 |

42 | 43 | Choose a file to upload: 44 | Choose a file to upload: 45 |

46 | 47 |
-------------------------------------------------------------------------------- /http/server/s3/src/main/resources/templates/api_en.properties: -------------------------------------------------------------------------------- 1 | welcome=Welcome to the Higgs Thymeleaf demo! -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/templates/api_es.properties: -------------------------------------------------------------------------------- 1 | welcome=Bienvenido a la demo Thymeleaf Higgs! -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/templates/api_fr.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zcourts/higgs/504504331ded8f276fc7862986747fdeff132d90/http/server/s3/src/main/resources/templates/api_fr.properties -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/templates/error/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 6 | 7 | 8 |

Error

9 | 10 | 11 | -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/templates/footer.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/templates/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Api Demo 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /http/server/s3/src/main/resources/templates/index.moustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Api Demo 5 | 6 | 7 | 8 | 9 | {{name}}, 10 |
{{feature.description}}! 11 | 12 | 13 | -------------------------------------------------------------------------------- /http/server/transformer-defaults/README.md: -------------------------------------------------------------------------------- 1 | # Default Transformers 2 | 3 | This module is a service provider which adds support for JSON and static files 4 | -------------------------------------------------------------------------------- /http/server/transformer-defaults/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | transformer-defaults 4 | ${project.artifactId} 5 | A service provider which implements the transformer interface for JSON and static files 6 | jar 7 | 8 | io.higgs 9 | http-server 10 | ../pom.xml 11 | 0.0.25-SNAPSHOT 12 | 13 | 14 | 15 | io.higgs 16 | http-s3 17 | 18 | 23 | 24 | org.kohsuke.metainf-services 25 | metainf-services 26 | 1.1 27 | true 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /http/server/transformer-defaults/src/main/java/io/higgs/http/server/transformers/ChunkedFileWriter.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.transformers; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.stream.ChunkedInput; 6 | 7 | import java.io.InputStream; 8 | 9 | /** 10 | * Used in place of Netty's {@link io.netty.handler.stream.ChunkedFile} so that we can use a pure input stream 11 | * as opposed to file objects. 12 | * 13 | * @author Courtney Robinson 14 | */ 15 | public class ChunkedFileWriter implements ChunkedInput { 16 | protected InputStream stream; 17 | protected int chunkSize; 18 | 19 | public ChunkedFileWriter(InputStream in, int chunkSize) { 20 | this.stream = in; 21 | this.chunkSize = chunkSize; 22 | } 23 | 24 | @Override 25 | public boolean isEndOfInput() throws Exception { 26 | return stream.available() == 0; 27 | } 28 | 29 | @Override 30 | public void close() throws Exception { 31 | stream.close(); 32 | } 33 | 34 | @Override 35 | public ByteBuf readChunk(ChannelHandlerContext ctx) throws Exception { 36 | ByteBuf buf = ctx.alloc().heapBuffer(chunkSize); 37 | int read = stream.read(buf.array()); 38 | buf.writerIndex(read); 39 | return buf; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /http/server/transformer-defaults/src/main/java/io/higgs/http/server/transformers/JsonResponseError.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.transformers; 2 | 3 | import io.netty.handler.codec.http.HttpResponseStatus; 4 | 5 | import javax.ws.rs.WebApplicationException; 6 | 7 | /** 8 | * @author Courtney Robinson 9 | */ 10 | public class JsonResponseError extends WebApplicationException { 11 | public static final String EMPTY_JSON_OBJECT = "{}"; 12 | protected Object content; 13 | 14 | public JsonResponseError(HttpResponseStatus status, Object content) { 15 | super(status.code()); 16 | this.content = content == null ? EMPTY_JSON_OBJECT : content; 17 | } 18 | 19 | public Object getContent() { 20 | return content; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /http/server/transformer-defaults/src/main/java/io/higgs/http/server/transformers/conf/FilesConfig.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.transformers.conf; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * @author Courtney Robinson 8 | */ 9 | public class FilesConfig { 10 | public boolean delete_temp_on_exit = true; 11 | //use default system temp dir if null 12 | public String temp_directory; 13 | //how big are the chunks when sending a file 14 | public int chunk_size = 8192; 15 | //colon separates each, comma, separates multiple extensions 16 | public Map custom_mime_types = new HashMap<>(); 17 | public int priority = -1; 18 | 19 | public FilesConfig() { 20 | //add some default mime types 21 | custom_mime_types.put("htm,html", "text/html"); 22 | custom_mime_types.put("json", "application/json"); 23 | custom_mime_types.put("xml", "application/xml"); 24 | custom_mime_types.put("png", "image/png"); 25 | custom_mime_types.put("css", "text/css"); 26 | custom_mime_types.put("js", "text/javascript"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /http/server/transformer-defaults/src/main/java/io/higgs/http/server/transformers/conf/JsonConfig.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.transformers.conf; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class JsonConfig { 7 | public int priority; 8 | } 9 | -------------------------------------------------------------------------------- /http/server/transformer-defaults/src/main/resources/json_config.yml: -------------------------------------------------------------------------------- 1 | # 1 less than thymeleaf's default 2 | priority: 0 3 | -------------------------------------------------------------------------------- /http/server/transformer-defaults/src/main/resources/public/index.html: -------------------------------------------------------------------------------- 1 |

Some random index file

-------------------------------------------------------------------------------- /http/server/transformer-defaults/src/main/resources/static_file_config.yml: -------------------------------------------------------------------------------- 1 | #should temp uploaded files be deleted 2 | delete_temp_on_exit : true 3 | #use default system temp dir if null 4 | temp_directory: 5 | #how big are the chunks when sending a static file 6 | chunk_size : 8192 7 | #a map of file extensions to their content type. 8 | #any file with one of these extensions is sent with the given content-type header 9 | custom_mime_types : 10 | htm,html : text/html 11 | json : application/json 12 | xml : application/xml 13 | png : image/png 14 | js : application/javascript 15 | css: text/css 16 | otf: font/opentype 17 | svg: image/svg+xml 18 | ttf: application/x-font-truetype 19 | otf: application/x-font-opentype 20 | woff: application/font-woff 21 | eot: application/vnd.ms-fontobject 22 | -------------------------------------------------------------------------------- /http/server/transformer-defaults/src/main/resources/templates/error/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 6 | 7 | 8 |

Error

9 | 10 | 11 | -------------------------------------------------------------------------------- /http/server/transformer-defaults/src/main/resources/templates/index.moustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Api Demo 5 | 6 | 7 | 8 | 9 | {{name}}, 10 |
{{feature.description}}! 11 | 12 | 13 | -------------------------------------------------------------------------------- /http/server/transformer-handlebars/README.md: -------------------------------------------------------------------------------- 1 | # Thymeleaf Transformer 2 | 3 | This module is a service provider which adds support for Thymeleaf as an HTML templating option. 4 | -------------------------------------------------------------------------------- /http/server/transformer-handlebars/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | transformer-handlebars 4 | ${project.artifactId} 5 | A service provider which implements the transformer interface 6 | jar 7 | 8 | io.higgs 9 | http-server 10 | ../pom.xml 11 | 0.0.25-SNAPSHOT 12 | 13 | 14 | 1.3.0 15 | 16 | 17 | 18 | io.higgs 19 | http-s3 20 | 21 | 22 | 23 | org.kohsuke.metainf-services 24 | metainf-services 25 | 1.1 26 | true 27 | 28 | 29 | 30 | com.github.jknack 31 | handlebars 32 | ${handlebars-version} 33 | 34 | 35 | com.fasterxml.jackson.core 36 | jackson-databind 37 | 38 | 39 | org.slf4j 40 | slf4j-api 41 | 42 | 43 | 44 | 45 | 46 | com.github.jknack 47 | handlebars-jackson2 48 | ${handlebars-version} 49 | 50 | 51 | com.fasterxml.jackson.core 52 | jackson-databind 53 | 54 | 55 | 56 | 57 | 58 | com.github.jknack 59 | handlebars-markdown 60 | ${handlebars-version} 61 | 62 | 63 | 64 | com.github.jknack 65 | handlebars-humanize 66 | ${handlebars-version} 67 | 68 | 69 | com.google.guava 70 | guava 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /http/server/transformer-handlebars/src/main/java/io/higgs/http/server/config/HandlebarsConfig.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.config; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class HandlebarsConfig { 7 | public int priority = 1; 8 | /** 9 | * The directory to check for handlebars templates 10 | */ 11 | public String directory = "templates"; 12 | /** 13 | * if the template name given to the template annotation doesn't have a file extension this is appended 14 | */ 15 | public String template = ".hbs"; 16 | 17 | public boolean cache_templates = true; 18 | 19 | public boolean enable_jackson_helper = true; 20 | public boolean enable_markdown_helper = true; 21 | public boolean enable_humanize_helper = true; 22 | } 23 | -------------------------------------------------------------------------------- /http/server/transformer-handlebars/src/main/java/io/higgs/http/server/transformers/handlebars/HandlebarHelper.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.transformers.handlebars; 2 | 3 | import com.github.jknack.handlebars.Helper; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public interface HandlebarHelper extends Helper { 9 | String getName(); 10 | } 11 | -------------------------------------------------------------------------------- /http/server/transformer-handlebars/src/main/java/io/higgs/http/server/transformers/handlebars/HiggsTemplateLoader.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.transformers.handlebars; 2 | 3 | import com.github.jknack.handlebars.io.TemplateLoader; 4 | import com.github.jknack.handlebars.io.TemplateSource; 5 | import io.higgs.core.FileUtil; 6 | import io.higgs.core.ResolvedFile; 7 | import io.higgs.http.server.config.HandlebarsConfig; 8 | 9 | import java.io.IOException; 10 | import java.nio.file.Path; 11 | import java.nio.file.Paths; 12 | 13 | /** 14 | * @author Courtney Robinson 15 | */ 16 | public class HiggsTemplateLoader implements TemplateLoader { 17 | protected HandlebarsConfig config; 18 | protected Path base; 19 | 20 | public HiggsTemplateLoader(HandlebarsConfig config) { 21 | this.config = config; 22 | base = Paths.get(config.directory); 23 | } 24 | 25 | @Override 26 | public TemplateSource sourceAt(String template) throws IOException { 27 | String ext = config.template; 28 | if (!template.endsWith(ext) || !template.contains(".")) { 29 | template = template + ext; 30 | } 31 | final ResolvedFile file = FileUtil.resolve(base, Paths.get(template)); 32 | if (!file.exists()) { 33 | throw new IOException(template + " not found"); 34 | } 35 | return new HiggsTemplateSource(file); 36 | } 37 | 38 | @Override 39 | public String resolve(String s) { 40 | return s; 41 | } 42 | 43 | @Override 44 | public String getPrefix() { 45 | return ""; 46 | } 47 | 48 | @Override 49 | public String getSuffix() { 50 | return config.template; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /http/server/transformer-handlebars/src/main/java/io/higgs/http/server/transformers/handlebars/HiggsTemplateSource.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.transformers.handlebars; 2 | 3 | import com.github.jknack.handlebars.io.TemplateSource; 4 | import com.google.common.base.Charsets; 5 | import io.higgs.core.ResolvedFile; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.IOException; 9 | import java.io.InputStreamReader; 10 | 11 | /** 12 | * @author Courtney Robinson 13 | */ 14 | public class HiggsTemplateSource implements TemplateSource { 15 | private final ResolvedFile file; 16 | private String data = ""; 17 | 18 | public HiggsTemplateSource(ResolvedFile file) { 19 | this.file = file; 20 | } 21 | 22 | public String content() throws IOException { 23 | if (data == null || data.isEmpty()) { 24 | BufferedReader reader = new BufferedReader(new InputStreamReader(file.getStream(), Charsets.UTF_8)); 25 | StringBuilder builder = new StringBuilder(); 26 | String line; 27 | while ((line = reader.readLine()) != null) { 28 | builder.append(line); 29 | } 30 | data = builder.toString(); 31 | } 32 | return data; 33 | } 34 | 35 | @Override 36 | public String filename() { 37 | return file.getName(); 38 | } 39 | 40 | @Override 41 | public long lastModified() { 42 | return file.lastModified(); 43 | } 44 | 45 | @Override 46 | public int hashCode() { 47 | int result = file != null ? file.hashCode() : 0; 48 | result = 31 * result + (data != null ? data.hashCode() : 0); 49 | return result; 50 | } 51 | 52 | @Override 53 | public boolean equals(Object o) { 54 | if (this == o) { 55 | return true; 56 | } 57 | if (o == null || getClass() != o.getClass()) { 58 | return false; 59 | } 60 | 61 | HiggsTemplateSource that = (HiggsTemplateSource) o; 62 | 63 | if (data != null ? !data.equals(that.data) : that.data != null) { 64 | return false; 65 | } 66 | if (file != null ? !file.equals(that.file) : that.file != null) { 67 | return false; 68 | } 69 | 70 | return true; 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /http/server/transformer-handlebars/src/main/resources/handlebars_config.yml: -------------------------------------------------------------------------------- 1 | #if other transformers are loaded at the same time as handlebars the priority decides which one is used if 2 | #there is another transformer which can convert the same types as handlebars the one with the highest priority wins 3 | priority: 2 4 | #the base directory to check for handlebars templates 5 | directory: templates 6 | #if true then if a response object is a map each key in the map becomes the name of a variable in the 7 | #handlebars scope with it's value set to the map's value for that key 8 | extract_values_from_maps: true 9 | #If true then when an object is returned that is not a collection or primitive the fields names in the object 10 | #become variables in the handlebars scope with the value of the variable being that of the field 11 | extract_pojo_fields: true 12 | # if the template name given to the template annotation doesn't have a file extension this is appended 13 | template: ".handlebars" 14 | #if true a template is loaded once from disk and cached in memory, otherwise it's fetched each time it's needed 15 | cache_templates: true 16 | enable_jackson_helper : true; 17 | enable_markdown_helper : true; 18 | enable_humanize_helper : true; 19 | -------------------------------------------------------------------------------- /http/server/transformer-handlebars/src/main/resources/templates/error/default.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error {{_response.status}} {{_response.response.statusInfo.reasonPhrase}}" 5 | 6 | 7 | 8 |

Error {{_response.response.status}}, {{_response.response.statusInfo.reasonPhrase}}

9 | 10 | 11 | -------------------------------------------------------------------------------- /http/server/transformer-mustache/README.md: -------------------------------------------------------------------------------- 1 | # Thymeleaf Transformer 2 | 3 | This module is a service provider which adds support for Thymeleaf as an HTML templating option. 4 | -------------------------------------------------------------------------------- /http/server/transformer-mustache/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | transformer-mustache 4 | ${project.artifactId} 5 | A service provider which implements the transformer interface 6 | jar 7 | 8 | io.higgs 9 | http-server 10 | ../pom.xml 11 | 0.0.25-SNAPSHOT 12 | 13 | 14 | 15 | io.higgs 16 | http-s3 17 | 18 | 19 | org.kohsuke.metainf-services 20 | metainf-services 21 | 1.1 22 | true 23 | 24 | 25 | 30 | 31 | com.github.spullara.mustache.java 32 | compiler 33 | 0.8.14 34 | 35 | 36 | com.google.guava 37 | guava 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /http/server/transformer-mustache/src/main/java/io/higgs/http/server/config/MustacheConfig.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.config; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class MustacheConfig { 7 | public int priority = 1; 8 | /** 9 | * The directory to check for mustache templates 10 | */ 11 | public String directory = "templates"; 12 | /** 13 | * if true then if a response object is a map each key in the map becomes the name of a variable in the 14 | * mustache scope with it's value set to the map's value for that key 15 | */ 16 | public boolean extract_values_from_maps = true; 17 | /** 18 | * If true then when an object is returned that is not a collection or primitive the fields names in the object 19 | * become variables in the mustache scope with the value of the variable being that of the field 20 | */ 21 | public boolean extract_pojo_fields = true; 22 | /** 23 | * if the template name given to the template annotation doesn't have a file extension this is appended 24 | */ 25 | public String template = ".mustache"; 26 | 27 | public boolean cache_templates = true; 28 | } 29 | -------------------------------------------------------------------------------- /http/server/transformer-mustache/src/main/java/io/higgs/http/server/transformers/mustache/HiggsMustacheFactory.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.transformers.mustache; 2 | 3 | import com.github.mustachejava.DefaultMustacheFactory; 4 | import com.github.mustachejava.Mustache; 5 | import com.github.mustachejava.MustacheException; 6 | import com.github.mustachejava.MustacheFactory; 7 | import com.google.common.base.Charsets; 8 | import com.google.common.util.concurrent.UncheckedExecutionException; 9 | import io.higgs.core.FileUtil; 10 | import io.higgs.core.ResolvedFile; 11 | import io.higgs.http.server.config.MustacheConfig; 12 | 13 | import java.io.BufferedReader; 14 | import java.io.InputStreamReader; 15 | import java.io.Reader; 16 | import java.nio.file.Path; 17 | import java.nio.file.Paths; 18 | 19 | /** 20 | * @author Courtney Robinson 21 | */ 22 | public class HiggsMustacheFactory extends DefaultMustacheFactory implements MustacheFactory { 23 | protected MustacheConfig config; 24 | protected Path base; 25 | 26 | public HiggsMustacheFactory(MustacheConfig config) { 27 | this.config = config; 28 | base = Paths.get(config.directory); 29 | } 30 | 31 | @Override 32 | public Reader getReader(String resourceName) { 33 | ResolvedFile file = FileUtil.resolve(base, Paths.get(resourceName)); 34 | if (!file.exists()) { 35 | throw new MustacheException(resourceName + " not found"); 36 | } 37 | return new BufferedReader(new InputStreamReader(file.getStream(), Charsets.UTF_8)); 38 | } 39 | 40 | public Mustache compile(String name) { 41 | if (config.cache_templates) { 42 | return super.compile(name); 43 | } 44 | try { 45 | Mustache mustache = mc.compile(name); 46 | mustache.init(); 47 | return mustache; 48 | } catch (UncheckedExecutionException e) { 49 | throw handle(e); 50 | } 51 | } 52 | 53 | private MustacheException handle(Exception e) { 54 | Throwable cause = e.getCause(); 55 | if (cause instanceof MustacheException) { 56 | return (MustacheException) cause; 57 | } 58 | return new MustacheException(cause); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /http/server/transformer-mustache/src/main/resources/mustache_config.yml: -------------------------------------------------------------------------------- 1 | #if other transformers are loaded at the same time as mustache the priority decides which one is used if 2 | #there is another transformer which can convert the same types as mustache the one with the highest priority wins 3 | priority: 2 4 | #the base directory to check for mustache templates 5 | directory: templates 6 | #if true then if a response object is a map each key in the map becomes the name of a variable in the 7 | #mustache scope with it's value set to the map's value for that key 8 | extract_values_from_maps: true 9 | #If true then when an object is returned that is not a collection or primitive the fields names in the object 10 | #become variables in the mustache scope with the value of the variable being that of the field 11 | extract_pojo_fields: true 12 | # if the template name given to the template annotation doesn't have a file extension this is appended 13 | template: ".mustache" 14 | #if true a template is loaded once from disk and cached in memory, otherwise it's fetched each time it's needed 15 | cache_templates: true 16 | -------------------------------------------------------------------------------- /http/server/transformer-mustache/src/main/resources/public/index.html: -------------------------------------------------------------------------------- 1 |

Some random index file

-------------------------------------------------------------------------------- /http/server/transformer-mustache/src/main/resources/templates/error/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 6 | 7 | 8 |

Error

9 | 10 | 11 | -------------------------------------------------------------------------------- /http/server/transformer-mustache/src/main/resources/templates/index.mustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Api Demo 5 | 6 | 7 | 8 | 9 | {{name}}, 10 |
{{feature.description}}! 11 | 12 | 13 | -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/README.md: -------------------------------------------------------------------------------- 1 | # Thymeleaf Transformer 2 | 3 | This module is a service provider which adds support for Thymeleaf as an HTML templating option. 4 | -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | transformer-thymeleaf 4 | ${project.artifactId} 5 | Higgs HTTP S3 (Single Site Server) 6 | jar 7 | 8 | io.higgs 9 | http-server 10 | ../pom.xml 11 | 0.0.25-SNAPSHOT 12 | 13 | 14 | 15 | io.higgs 16 | http-s3 17 | 18 | 23 | 24 | org.kohsuke.metainf-services 25 | metainf-services 26 | 1.1 27 | true 28 | 29 | 30 | 31 | org.thymeleaf 32 | thymeleaf 33 | 2.0.15 34 | 35 | 36 | org.javassist 37 | javassist 38 | 39 | 40 | org.slf4j 41 | slf4j-api 42 | 43 | 44 | com.google.guava 45 | guava 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/java/io/higgs/http/server/config/TemplateConfig.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.config; 2 | 3 | /** 4 | * @author Courtney Robinson 5 | */ 6 | public class TemplateConfig { 7 | 8 | public boolean cacheable = true; 9 | /** 10 | * 24hrs by default 11 | * Max time to cache templates for (in Milliseconds) 12 | */ 13 | public long cache_age_ms = 86400000; 14 | /** 15 | * Char encoding used when reading templates 16 | */ 17 | public String character_encoding = "utf-8"; 18 | public String suffix = ".html"; 19 | /** 20 | * Sets a new (optional) prefix to be added to all template names in order to convert template names into 21 | * resource names. 22 | */ 23 | public String prefix = "templates/"; 24 | public Integer classLoader_resolver_order = 1; 25 | public Integer fileResolver_order = 2; 26 | public Integer url_resolver_order = 3; 27 | public boolean convert_map_responses_to_key_value_pairs = true; 28 | public boolean convert_pojo_responses_to_key_value_pairs = true; 29 | public boolean auto_initialize_thymeleaf = true; 30 | public boolean determine_language_from_accept_header = true; 31 | public String auto_parse_extensions = "html,htm"; 32 | 33 | public String template_mode = "HTML5"; 34 | /** 35 | * If true then template fragments are merged on each request. 36 | * If false then fragments are merged once at start up 37 | */ 38 | public boolean merge_fragments_on_each_request = true; 39 | public String fragments_dir = "merged-fragments/"; 40 | /** 41 | * Determines the order in which the thymleaf transformer is used to convert a response object 42 | */ 43 | public int priority = 1; 44 | } 45 | -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/java/io/higgs/http/server/transformers/thymeleaf/WebContext.java: -------------------------------------------------------------------------------- 1 | package io.higgs.http.server.transformers.thymeleaf; 2 | 3 | import org.thymeleaf.context.Context; 4 | 5 | /** 6 | * @author Courtney Robinson 7 | */ 8 | public class WebContext extends Context { 9 | } 10 | -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | #reduce the thymeleaf logging to warnings or above 2 | log4j.logger.org.thymeleaf = WARN 3 | # Root logger option 4 | log4j.rootLogger=INFO, file, stdout 5 | 6 | # Direct log messages to a log file 7 | log4j.appender.file=org.apache.log4j.RollingFileAppender 8 | log4j.appender.file.File=./var/log/hs3.log 9 | log4j.appender.file.MaxFileSize=100MB 10 | log4j.appender.file.MaxBackupIndex=5 11 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 12 | log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 13 | 14 | # Direct log messages to stdout 15 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 16 | log4j.appender.stdout.Target=System.out 17 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 18 | log4j.appender.stdout.layout.ConversionPattern=%C %d{ABSOLUTE} %5p %c{1}:%L - %m%n 19 | 20 | #make request_logger output format different from normal logs 21 | log4j.logger.request_logger=DEBUG, request_logger_console,request_logger_file 22 | #prevent request logs from propagating to the root logger 23 | log4j.additivity.request_logger=false 24 | 25 | log4j.appender.request_logger_console=org.apache.log4j.ConsoleAppender 26 | log4j.appender.request_logger_console.layout=org.apache.log4j.PatternLayout 27 | log4j.appender.request_logger_console.layout.ConversionPattern=%m%n 28 | 29 | log4j.appender.request_logger_file=org.apache.log4j.RollingFileAppender 30 | log4j.appender.request_logger_file.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.request_logger_file.layout.ConversionPattern=%m%n 32 | 33 | log4j.appender.request_logger_file.File=./var/log/hs3-requests.log 34 | log4j.appender.request_logger_file.MaxFileSize=100MB 35 | log4j.appender.request_logger_file.MaxBackupIndex=5 -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/public/default.html: -------------------------------------------------------------------------------- 1 |

Default file

-------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/public/demo.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | Static file demo -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zcourts/higgs/504504331ded8f276fc7862986747fdeff132d90/http/server/transformer-thymeleaf/src/main/resources/public/favicon.ico -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/public/header.html: -------------------------------------------------------------------------------- 1 | HTML header to be included in other templates. -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/public/index.html: -------------------------------------------------------------------------------- 1 |

Some random index file

-------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/public/sub/defaultt.html: -------------------------------------------------------------------------------- 1 |

Index in sub directory

-------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/public/sub/random.html: -------------------------------------------------------------------------------- 1 | Just random -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/templates/api.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
Default template variable nameSize
${_query.size}${_query.size}
${_form.size}${_form.size}
${_files.size}${_files.size}
${_session}${_session.size}
${_cookies.size}${_cookies.size}
${_response}${_response}
34 | 35 |

Welcome to the Higgs Thymeleaf demo!

36 | 37 |
38 |

39 | Type some text (if you like):

40 | 41 |

42 | 43 | Choose a file to upload: 44 | Choose a file to upload: 45 |

46 | 47 |
-------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/templates/api_en.properties: -------------------------------------------------------------------------------- 1 | welcome=Welcome to the Higgs Thymeleaf demo! -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/templates/api_es.properties: -------------------------------------------------------------------------------- 1 | welcome=Bienvenido a la demo Thymeleaf Higgs! -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/templates/api_fr.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zcourts/higgs/504504331ded8f276fc7862986747fdeff132d90/http/server/transformer-thymeleaf/src/main/resources/templates/api_fr.properties -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/templates/error/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 6 | 7 | 8 |

Error

9 | 10 | 11 | -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/templates/footer.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/templates/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Api Demo 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/templates/index.moustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Api Demo 5 | 6 | 7 | 8 | 9 | {{name}}, 10 |
{{feature.description}}! 11 | 12 | 13 | -------------------------------------------------------------------------------- /http/server/transformer-thymeleaf/src/main/resources/thymeleaf_config.yml: -------------------------------------------------------------------------------- 1 | #when static files are being served, files with the following extensions will be passed through 2 | #thymelead first so that thymeleaf directives can be processed 3 | #these must be valid Java regex values 4 | auto_parse_extensions : ".*html,.*htm,.*tpl" 5 | #Thymeleaf template mode on of Thymeleaf's supported XML,VALIDXML,XHTML,VALIDXHTML,LEGACYHTML5,HTML5 6 | template_mode : HTML5 7 | #if true templates are cache after first load 8 | cacheable : true 9 | #24hrs in milliseconds (max time a template is cached for) 10 | cache_age_ms : 86400000 11 | #encoding used to read template files 12 | character_encoding : utf-8 13 | #suffix appended to all templates so that index becomes defaultt.html 14 | suffix : .html 15 | #prefix prepended to all templates. can be directory or string...or both 16 | prefix : templates/ 17 | #the resolvers determine how a template is loaded and in which order 18 | #if 1 then try to load templates from the class path first 19 | classLoader_resolver_order : 2 20 | #try to load templates after class path if template not found 21 | fileResolver_order : 1 22 | url_resolver_order : 3 23 | #when a resource returns a map, should the map's keys become template variable names? 24 | convert_map_responses_to_key_value_pairs : true 25 | #when a resource returns a pojo (not primitive, list,map,set or array) 26 | #should it's fields become template variables? 27 | convert_pojo_responses_to_key_value_pairs : true 28 | #thymeleaf shouldn't be configured after initialization. set this to false if you need to 29 | #do additional configuration, such as add a dialect etc... 30 | auto_initialize_thymeleaf : true 31 | #if true then thymeleaf's locale is set to the locale obtained from the Accept-Language http header 32 | #if you use multiple language files it will load one based on this locale 33 | determine_language_from_accept_header : true 34 | #if true then whenever a method specifies multiple templates those templates are merged into one file before being passed to Thymleaf 35 | #this allows invalid/incomplete fragments HTML to be put into different files and combined to form a complete template 36 | #if this is false then the fragments are only combined the first time the resource is requested or if a combined file doesn't exist already 37 | #note that when merged together fragments must form a valid document for the template_mode set otherwise Thymeleaf will throw an exception 38 | merge_fragments_on_each_request : true 39 | #a directory where generated templates are created. this is relative to the "prefix" option 40 | fragments_dir : "merged-fragments/" 41 | -------------------------------------------------------------------------------- /websocket/README.md: -------------------------------------------------------------------------------- 1 | # Higgs WebSocket 2 | 3 | Containing project for the Higgs web socket modules 4 | -------------------------------------------------------------------------------- /websocket/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | ws-client 4 | ${project.artifactId} 5 | Higgs HTTP Client 6 | jar 7 | 8 | io.higgs 9 | websocket 10 | ../pom.xml 11 | 0.0.25-SNAPSHOT 12 | 13 | 14 | 15 | io.higgs 16 | http-client 17 | 18 | 19 | io.higgs 20 | events 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /websocket/client/src/main/java/io/higgs/ws/client/WebSocketEventListener.java: -------------------------------------------------------------------------------- 1 | package io.higgs.ws.client; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.handler.codec.http.FullHttpResponse; 5 | import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; 6 | import io.netty.handler.codec.http.websocketx.PingWebSocketFrame; 7 | 8 | /** 9 | * @author Courtney Robinson 10 | */ 11 | public interface WebSocketEventListener { 12 | /** 13 | * Invoked when a connection is established 14 | * 15 | * @param ctx available ctx 16 | */ 17 | void onConnect(ChannelHandlerContext ctx); 18 | 19 | /** 20 | * Invoked when the connection is closed for whatever reason 21 | * 22 | * @param ctx available ctx 23 | * @param frame If available this may contain a reason why the connection is closed. Not always provided,can be null 24 | */ 25 | void onClose(ChannelHandlerContext ctx, CloseWebSocketFrame frame); 26 | 27 | /** 28 | * Invoked when a heart beat is sent to keep the connection alive, typically. 29 | * 30 | * @param ctx available ctx 31 | * @param frame any data sent in the ping, clients are expected to send a 32 | * {@link io.netty.handler.codec.http.websocketx.PongWebSocketFrame} in response to the ping 33 | */ 34 | void onPing(ChannelHandlerContext ctx, PingWebSocketFrame frame); 35 | 36 | /** 37 | * Invoked when a message is received 38 | * 39 | * @param ctx available ctx 40 | * @param msg the data received 41 | */ 42 | void onMessage(ChannelHandlerContext ctx, WebSocketMessage msg); 43 | 44 | /** 45 | * Invoked for any un-caught exception thrown in the pipeline 46 | * 47 | * @param ctx available ctx 48 | * @param cause the exception that caused this to be invoked 49 | * @param response the response received, IFF available 50 | */ 51 | void onError(ChannelHandlerContext ctx, Throwable cause, FullHttpResponse response); 52 | } 53 | -------------------------------------------------------------------------------- /websocket/client/src/main/java/io/higgs/ws/client/WebSocketMessage.java: -------------------------------------------------------------------------------- 1 | package io.higgs.ws.client; 2 | 3 | import java.io.IOException; 4 | 5 | import static io.higgs.ws.client.WebSocketClient.MAPPER; 6 | 7 | /** 8 | * @author Courtney Robinson 9 | */ 10 | public class WebSocketMessage { 11 | protected final String data; 12 | 13 | public WebSocketMessage(String text) { 14 | this.data = text; 15 | } 16 | 17 | public String data() { 18 | return data; 19 | } 20 | 21 | /** 22 | * Convert this web socket object to an instance of the given class 23 | * 24 | * @param klass the class to create an instance of 25 | * @return an instance of the given class created from the data or null if an erro occurred 26 | */ 27 | public T as(Class klass) { 28 | try { 29 | return MAPPER.readValue(data, klass); 30 | } catch (IOException e) { 31 | return null; 32 | } 33 | } 34 | 35 | public String toString() { 36 | return data; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /websocket/client/src/main/java/io/higgs/ws/client/WebSocketServerEventListener.java: -------------------------------------------------------------------------------- 1 | package io.higgs.ws.client; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.handler.codec.http.websocketx.PongWebSocketFrame; 5 | 6 | /** 7 | * @author Courtney Robinson 8 | */ 9 | public interface WebSocketServerEventListener extends WebSocketEventListener { 10 | /** 11 | * Invoked when a {@link io.netty.handler.codec.http.websocketx.PingWebSocketFrame} is received 12 | * 13 | * @param ctx available ctx 14 | * @param frame the data sent back in response to a ping 15 | */ 16 | void onPong(ChannelHandlerContext ctx, PongWebSocketFrame frame); 17 | } 18 | -------------------------------------------------------------------------------- /websocket/client/src/main/java/io/higgs/ws/client/WebSocketStream.java: -------------------------------------------------------------------------------- 1 | package io.higgs.ws.client; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelFuture; 6 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 7 | import io.netty.util.concurrent.GenericFutureListener; 8 | 9 | import java.net.URI; 10 | import java.util.Set; 11 | 12 | import static io.higgs.ws.client.WebSocketClient.MAPPER; 13 | 14 | /** 15 | * @author Courtney Robinson 16 | */ 17 | public class WebSocketStream { 18 | protected final ChannelFuture future; 19 | protected final URI uri; 20 | protected final Set listeners; 21 | protected Channel channel; 22 | 23 | public WebSocketStream(URI uri, ChannelFuture cf, Set listeners) { 24 | this.uri = uri; 25 | this.future = cf; 26 | this.listeners = listeners; 27 | cf.addListener(new GenericFutureListener() { 28 | public void operationComplete(ChannelFuture future) throws Exception { 29 | if (future.isSuccess()) { 30 | channel = future.channel(); 31 | } 32 | } 33 | }); 34 | } 35 | 36 | public WebSocketStream subscribe(WebSocketEventListener listener) { 37 | listeners.add(listener); 38 | return this; 39 | } 40 | 41 | /** 42 | * Send a message to the server 43 | * 44 | * @param message the message to send 45 | * @return 46 | */ 47 | public ChannelFuture send(String message) { 48 | if (channel == null || !channel.isActive()) { 49 | throw new IllegalStateException("Not connected"); 50 | } 51 | return channel.writeAndFlush(new TextWebSocketFrame(message)); 52 | } 53 | 54 | /** 55 | * Send a message to the server 56 | * 57 | * @param message the message to send 58 | * @return a future or null if an error occurred 59 | */ 60 | public ChannelFuture send(Object message) { 61 | if (channel == null || !channel.isActive()) { 62 | throw new IllegalStateException("Not connected"); 63 | } 64 | try { 65 | return channel.writeAndFlush(new TextWebSocketFrame(MAPPER.writeValueAsString(message))); 66 | } catch (final JsonProcessingException e) { 67 | return null; 68 | } 69 | } 70 | 71 | /** 72 | * @return The future obtained from the connection attempt. 73 | * Subscribe for notification of completion or error 74 | */ 75 | public ChannelFuture connectFuture() { 76 | return future; 77 | } 78 | 79 | public Channel channel() { 80 | return channel; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /websocket/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | websocket 4 | ${project.artifactId} 5 | pom 6 | Higgs' WebSocket server and client implementation 7 | 8 | 9 | io.higgs 10 | higgs 11 | ../pom.xml 12 | 0.0.25-SNAPSHOT 13 | 14 | 15 | server 16 | client 17 | 18 | 19 | 20 | io.higgs 21 | core 22 | 23 | 24 | io.higgs 25 | http-s3 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /websocket/server/README.md: -------------------------------------------------------------------------------- 1 | # Higgs WebSocket 2 | 3 | Provides an implementation of a WebSocket server. 4 | The Server can be used to server both HTTP and WebSocket requests on the same port or even at the same path. 5 | It automatically detects the request type and handles it with an appropriate response. 6 | 7 | # Server 8 | 9 | ```java 10 | 11 | public class WebSocketServerDemo { 12 | static int count = 0; 13 | 14 | public static void main(String... args) { 15 | WebSocketServer server = new WebSocketServer(3535); 16 | server.HTTP.register(Api.class); 17 | server.listen("test", new Function1>() { 18 | public void apply(final ChannelMessage a) { 19 | System.out.println(++count + " : " + a.message); 20 | } 21 | }); 22 | server.bind(); 23 | } 24 | } 25 | 26 | ``` 27 | ## Output 28 | 29 | ```javascript 30 | 31 | 1 : TextEvent{message='{}', path='test'} 32 | 2 : TextEvent{message='{}', path='test'} 33 | 3 : TextEvent{message='{}', path='test'} 34 | 35 | ``` 36 | 37 | # Client 38 | Not implemented yet. On the TODO list. -------------------------------------------------------------------------------- /websocket/server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | ws-server 4 | ${project.artifactId} 5 | jar 6 | Higgs' WebSocket server implementation 7 | 8 | 9 | io.higgs 10 | websocket 11 | ../pom.xml 12 | 0.0.25-SNAPSHOT 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /websocket/server/src/main/java/io/higgs/ws/WebSocketEventHandler.java: -------------------------------------------------------------------------------- 1 | package io.higgs.ws; 2 | 3 | import io.higgs.core.InvokableMethod; 4 | import io.higgs.ws.protocol.WebSocketConfiguration; 5 | import io.higgs.ws.protocol.WebSocketHandler; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 8 | 9 | import java.util.Queue; 10 | 11 | /** 12 | * @author Courtney Robinson 13 | */ 14 | public interface WebSocketEventHandler { 15 | void onMessage(TextWebSocketFrame frame, WebSocketHandler webSocketHandler, ChannelHandlerContext ctx, 16 | Queue methods, WebSocketConfiguration config); 17 | } 18 | -------------------------------------------------------------------------------- /websocket/server/src/main/java/io/higgs/ws/protocol/WebSocketConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.higgs.ws.protocol; 2 | 3 | import io.higgs.core.ProtocolDetectorFactory; 4 | import io.higgs.http.server.protocol.HttpProtocolConfiguration; 5 | import io.higgs.ws.DefaultWebSocketEventHandler; 6 | import io.higgs.ws.WebSocketEventHandler; 7 | 8 | public class WebSocketConfiguration extends HttpProtocolConfiguration { 9 | private String websocketPath = "/"; 10 | private WebSocketEventHandler webSocketEventHandler; 11 | 12 | @Override 13 | public ProtocolDetectorFactory getProtocol() { 14 | //this is the method to override to provide a WebSocket detector 15 | return new WebSocketDetectorFactory(this); 16 | } 17 | 18 | public String getWebsocketPath() { 19 | return websocketPath; 20 | } 21 | 22 | public void setWebsocketPath(String websocketPath) { 23 | this.websocketPath = websocketPath; 24 | } 25 | 26 | public WebSocketEventHandler getWebSocketEventHandler() { 27 | return webSocketEventHandler == null ? new DefaultWebSocketEventHandler() : webSocketEventHandler; 28 | } 29 | 30 | public void setWebSocketEventHandler(WebSocketEventHandler webSocketEventHandler) { 31 | this.webSocketEventHandler = webSocketEventHandler; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /websocket/server/src/main/java/io/higgs/ws/protocol/WebSocketDetector.java: -------------------------------------------------------------------------------- 1 | package io.higgs.ws.protocol; 2 | 3 | import io.higgs.http.server.HttpRequestDecoder; 4 | import io.higgs.http.server.HttpResponseEncoder; 5 | import io.higgs.http.server.protocol.HttpDetector; 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.ChannelPipeline; 9 | import io.netty.handler.codec.http.HttpObjectAggregator; 10 | import io.netty.handler.stream.ChunkedWriteHandler; 11 | 12 | /** 13 | * An HTTP detector which only handles GET requests 14 | * 15 | * @author Courtney Robinson 16 | */ 17 | public class WebSocketDetector extends HttpDetector { 18 | protected final WebSocketConfiguration config; 19 | 20 | public WebSocketDetector(WebSocketConfiguration config) { 21 | super(config); 22 | this.config = config; 23 | } 24 | 25 | @Override 26 | public boolean detected(ChannelHandlerContext ctx, ByteBuf in) { 27 | final int magic1 = in.getUnsignedByte(in.readerIndex()); 28 | final int magic2 = in.getUnsignedByte(in.readerIndex() + 1); 29 | return magic1 == 'G' && magic2 == 'E'; //GET request 30 | } 31 | 32 | @Override 33 | public WebSocketHandler setupPipeline(ChannelPipeline p, ChannelHandlerContext ctx) { 34 | //WebSocketHandler is stateful so must do an instance per request/channel 35 | WebSocketHandler h = new WebSocketHandler(config); 36 | p.addLast("ws-decoder", new HttpRequestDecoder(config)); 37 | p.addLast("ws-aggregator", new HttpObjectAggregator(65536)); 38 | p.addLast("ws-encoder", new HttpResponseEncoder()); 39 | p.addLast("ws-chunkedWriter", new ChunkedWriteHandler()); 40 | p.addLast("ws-handler", h); 41 | return h; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /websocket/server/src/main/java/io/higgs/ws/protocol/WebSocketDetectorFactory.java: -------------------------------------------------------------------------------- 1 | package io.higgs.ws.protocol; 2 | 3 | import io.higgs.core.ProtocolDetector; 4 | import io.higgs.http.server.protocol.HttpDetectorFactory; 5 | 6 | /** 7 | * @author Courtney Robinson 8 | */ 9 | public class WebSocketDetectorFactory extends HttpDetectorFactory { 10 | private final WebSocketConfiguration config; 11 | 12 | public WebSocketDetectorFactory(WebSocketConfiguration config) { 13 | super(config); 14 | this.config = config; 15 | } 16 | 17 | @Override 18 | public ProtocolDetector newProtocolDetector() { 19 | return new WebSocketDetector(config); 20 | } 21 | 22 | @Override 23 | public int priority() { 24 | return 1; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /websocket/server/src/main/java/io/higgs/ws/sockjs/SockJSProtocol.java: -------------------------------------------------------------------------------- 1 | package io.higgs.ws.sockjs; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.Random; 8 | 9 | /** 10 | * @author Courtney Robinson 11 | */ 12 | @Path("sockjs") 13 | public class SockJSProtocol { 14 | 15 | private Random random = new Random(); 16 | 17 | @GET 18 | public Map info() { 19 | Map data = new HashMap<>(); 20 | //Are websockets enabled on the server? 21 | data.put("websocket", true); 22 | //Do transports need to support cookies (ie: for load balancing purposes. 23 | data.put("cookie_needed", true); 24 | data.put("origins", "*:*"); 25 | data.put("entropy", random.nextInt()); 26 | 27 | return data; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /websocket/server/src/main/resources/flash-policy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /websocket/server/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | #reduce the thymeleaf logging to warnings or above 2 | log4j.logger.org.thymeleaf = WARN 3 | # Root logger option 4 | log4j.rootLogger=INFO, file, stdout 5 | 6 | # Direct log messages to a log file 7 | log4j.appender.file=org.apache.log4j.RollingFileAppender 8 | log4j.appender.file.File=./var/log/hs3.log 9 | log4j.appender.file.MaxFileSize=100MB 10 | log4j.appender.file.MaxBackupIndex=5 11 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 12 | log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n 13 | 14 | # Direct log messages to stdout 15 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 16 | log4j.appender.stdout.Target=System.out 17 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 18 | log4j.appender.stdout.layout.ConversionPattern=%C %d{ABSOLUTE} %5p %c{1}:%L - %m%n 19 | 20 | #make request_logger output format different from normal logs 21 | log4j.logger.request_logger=DEBUG, request_logger_console,request_logger_file 22 | #prevent request logs from propagating to the root logger 23 | log4j.additivity.request_logger=false 24 | 25 | log4j.appender.request_logger_console=org.apache.log4j.ConsoleAppender 26 | log4j.appender.request_logger_console.layout=org.apache.log4j.PatternLayout 27 | log4j.appender.request_logger_console.layout.ConversionPattern=%m%n 28 | 29 | log4j.appender.request_logger_file=org.apache.log4j.RollingFileAppender 30 | log4j.appender.request_logger_file.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.request_logger_file.layout.ConversionPattern=%m%n 32 | 33 | log4j.appender.request_logger_file.File=./var/log/hs3-requests.log 34 | log4j.appender.request_logger_file.MaxFileSize=100MB 35 | log4j.appender.request_logger_file.MaxBackupIndex=5 -------------------------------------------------------------------------------- /websocket/server/src/main/resources/public/default.html: -------------------------------------------------------------------------------- 1 |

Default file

-------------------------------------------------------------------------------- /websocket/server/src/main/resources/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zcourts/higgs/504504331ded8f276fc7862986747fdeff132d90/websocket/server/src/main/resources/public/favicon.ico -------------------------------------------------------------------------------- /websocket/server/src/main/resources/public/index.html: -------------------------------------------------------------------------------- 1 |

Some random index file

-------------------------------------------------------------------------------- /websocket/server/src/main/resources/public/sub/defaultt.html: -------------------------------------------------------------------------------- 1 |

Index in sub directory

-------------------------------------------------------------------------------- /websocket/server/src/main/resources/public/sub/random.html: -------------------------------------------------------------------------------- 1 | Just random -------------------------------------------------------------------------------- /websocket/server/src/main/resources/templates/api.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Api Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
Default template variable nameSize
${_query.size}${_query.size}
${_form.size}${_form.size}
${_files.size}${_files.size}
${_session}${_session.size}
${_cookies.size}${_cookies.size}
${_response}${_response}
42 | 43 |

Welcome to the Higgs Thymeleaf demo!

44 | 45 |
46 |

47 | Type some text (if you like):

48 | 49 |

50 | 51 | Choose a file to upload: 52 | Choose a file to upload: 53 |

54 | 55 |
56 | 57 | 58 | -------------------------------------------------------------------------------- /websocket/server/src/main/resources/templates/api_en.properties: -------------------------------------------------------------------------------- 1 | welcome=Welcome to the Higgs Thymeleaf demo! -------------------------------------------------------------------------------- /websocket/server/src/main/resources/templates/api_es.properties: -------------------------------------------------------------------------------- 1 | welcome=Bienvenido a la demo Thymeleaf Higgs! -------------------------------------------------------------------------------- /websocket/server/src/main/resources/templates/api_fr.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zcourts/higgs/504504331ded8f276fc7862986747fdeff132d90/websocket/server/src/main/resources/templates/api_fr.properties -------------------------------------------------------------------------------- /websocket/server/src/main/resources/templates/error/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 6 | 7 | 8 |

Error

9 | 10 | 11 | -------------------------------------------------------------------------------- /websocket/server/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Api Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
Default template variable nameSize
${_query.size}${_query.size}
${_form.size}${_form.size}
${_files.size}${_files.size}
${_cookies.size}${_cookies.size}
${_request.classMethod.name}${_request.classMethod}
${_server.config.port}${_server.config.port}
${_response}${_response}
50 | 51 |

Higgs FlashWebSocket bridge API

52 | 53 |

Welcome to the Higgs Thymeleaf demo!

54 | The purpose of this is to show both HTML and WebSocket served from the same path, i.e. / 55 | 56 |
57 |

58 | Type some text (if you like):

59 | 60 |

61 | 62 | Choose a file to upload: 63 | Choose a file to upload: 64 |

65 | 66 |
67 | 68 | 69 | --------------------------------------------------------------------------------