Giter Site home page Giter Site logo

minjing / uapi Goto Github PK

View Code? Open in Web Editor NEW
4.0 4.0 5.0 2.6 MB

The UAPI Project

License: GNU General Public License v3.0

Java 78.68% Shell 0.02% Batchfile 0.01% FreeMarker 0.99% Groovy 20.19% JavaScript 0.11%
java service-injection uapi di-framework configuration-injection

uapi's Introduction

._  _.  _  .___.___
| || | / \ | _ | |
| || |/ _ \| __| |
|____/_/ \_|_|  _|_

Note the project was moved to Inactionware repo and separated as more subprojects, many codes were rewrited, have fun!

UAPI (Universal Application Platform Infrastructure)

Join the chat at https://gitter.im/minjing/uapi Build Status Codacy Badge Code Coverage

Stories in Ready

Introduction

Welcome to UAPI project!

The UAPI project will provide a generic platform/framework and some basic facilities to make build application easier and faster.

It contains below components:

  • Kernel - The framework core, it contains a extensible code generation framework based on java APT to support DI.
  • Service - Support Spring bean, remote service injection.
  • Config - The configuration framework
  • Log - The log framework
  • Event/Behavior - A event driven behavior framework
  • Web - The web framework to support RESTful service

This framework is still under developing, most features are unstable and the APIs may be changed frequently, welcome to evaluate and give me the feedback

A DI framework

The core component of UAPI is a DI framework which is Annotation based.

Inject Service by type

Declare a managed service first:

@Service
public class Greeting {
    public void greeting() {
        System.out.print("Hello!");
    }
}

Then you can reference the service from other service

@Service
public class SayGreeting {

    @Inject
    Greeting _greeting;

    public void sayGreeting() {
        this._greeting.greeting();
    }
}

The @Inject annotation will make DI framework inject Greeting service into SayGreeting service.

Inject service by name

In default the service injection is service type based, but sometime you may want to inject service by its name, you can follow:

@Service(ids="greeting")
public class Greeting {
    public void greeting() {
        System.out.print("Hello!");
    }
}

@Service
public class SayGreeting {

    @Inject("greeting")
    Greeting _greeting;

    public void sayGreeting() {
        this._greeting.greeting();
    }
}

Use Service Factory

In general, the service is singleton, which mean if multiple services reference one service A, only one service A instance is injected to multiple services. So if you want to multiple services reference different service A instance, you can use IServiceFactory:

@Service
public class GreetingFactory implement IServiceFactory<Greeting> {

    @Override
    public Greeting createService(Object serveFor) {
        return new Greeting();
    }
}

The serveFor tell the factory that which service will reference the created service.

Configuration

Most of application is configurable, so the configuration is basic functionality. UAPI support simple configuration injection.

Inject simple configuration

For some basic configuration item like String, int, double..., they can be injected directly by Config annotation:

@Service
public class ConfigurableService {

    @Config(path="name")
    String _name;

    @Config(path="age")
    int _age;

    @Inject
    ILogger _logger;

    @Inject
    IRegistry _svcReg;

    @Init
    public void init() {
        this._logger.info("Configured {} = {}", "name", this._name);
        this._logger.info("Configured {} = {}", "age", this._age);
        this._logger.info("Configured {} = {}", "address", this._address);
    }
}

The ConfigurableService declare it depends on two configurations: name and age, the configuration path is name and age. But where are the configurations defined? Ok, let's defined it in a yaml file named config.yml which is put in application conf folder:

name: Hello
age: 22

And then you need launch application with *-config=conf/config.yml" option, the configuration will be inject to the service automatically.

Note: The IRegistry is required, since the Configuration framework need use it to find out dependent service.

Inject complex configuration

For some complex configuration object, you may want to access it by Java object, you can using a configuration parser:

@Service
public class ConfigurableService {

    @Config(path="address", parser=AddressParser.class)
    Address _address;

    @Inject
    ILogger _logger;

    @Inject
    IRegistry _svcReg;

    @Init
    public void init() {
        this._logger.info("Configured {} = {}", "address", this._address);
    }
}

The config object and its parser:

public class Address {

    public String home;
    public String office;

    public String toString() {
        return "home=" + home + ",office=" + office;
    }
}

@Service(IConfigValueParser.class)
public class AddressParser implements IConfigValueParser {

    private static final String[] supportedTypesIn = new String[] {
            List.class.getCanonicalName()
    };
    private static final String[] supportedTypesOut = new String[] {
            Address.class.getCanonicalName()
    };

    @Override
    public boolean isSupport(String inType, String outType) {
        return CollectionHelper.isContains(supportedTypesIn, inType) && CollectionHelper.isContains(supportedTypesOut, outType);
    }

    @Override
    public String getName() {
        return AddressParser.class.getCanonicalName();
    }

    @Override
    public Address parse(Object value) {
        List<Map> addrList = (List<Map>) value;
        Address address = new Address();
        for (Map addr : addrList) {
            if (addr.get("home") != null) {
                address.home = addr.get("home").toString();
            }
            if (addr.get("office") != null) {
                address.office = addr.get("office").toString();
            }
        }
        return address;
    }
}

The configuration framework will try to find the parser from IRegistry, if it is found then the framework will try use it to parse the configurations and inject to the service.

Web framework

RESTful service

UAPI Web framework embed a Servlet container (Jetty) to provide HTTP service, it support expose a normal service to a RESTful service:

@Service(IRestfulService.class)
@Exposure("hello")
public class HelloRestful {

    @Restful(HttpMethod.Get)
    public String sayHello(
            @FromUri(0) String name,
            @FromParam("test") String test
    ) {
        return "Hello " + name + ", " + test;
    }
}

The Web framework is developing, it will be a part of remote service framework, when remote service framework done then you can inject a RESTful service into your service like inject a local service without any http invocation knowledge.

The service will be exposed as a RESTful service, the access URL like: http://localhost/restful/hello/[name]?test=test The @Exposure declare the service will be exposed as RESTful service with "hello" context. The [name] will be mapped to name argument of sayHello methodInfo, and the test query parameter will be mapped to test argument of sayHello methodInfo.

Remote service invocation based on Restful

Define an interface

To invoke a service remotely, the interface must be defined:

public interface IHello {

    String sayHello(String name, String title);
}

Expose service via Restful

@Service(IHello.class)
@Exposure("hello")
public class HelloRestful implements IHello {

    @Override
    @Restful(HttpMethod.Get)
    public String sayHello(
            @FromUri(0) String name,
            @FromParam("title") String title
    ) {
        return StringHelper.makeString("Hello {} {}", title, name);
    }
}

The HelloRestful implement IHello interface, the framework will detect this, and generate the interface description for it, in default it will be register to http://[host]:[port]/[context]?interface=[interface name]. For above example, you can enter URL: http://localhost/rest?interface=uapi.sample.hello.IHello, the response text is JSON based:

{
    "code": "000",
    "data": {
        "communication": "Restful",
        "interfaceId": "uapi.sample.hello.IHello",
        "serviceMetas": [{
            "argumentMetas": [{
                "from": "Uri",
                "index": 0,
                "typeName": "java.lang.String"
            }, {
                "from": "Param",
                "index": 0,
                "name": "title",
                "typeName": "java.lang.String"
            }],
            "codec": "JSON",
            "context": "rest",
            "host": "127.0.0.1",
            "id": "hello",
            "methods": ["GET"],
            "name": "sayHello",
            "port": 8080,
            "returnTypeName": "java.lang.String"
        }]
    }
}

The response JSON will reflect the registered service meta data including service parameters, the return type and communication information.

Client code to invoke remote service

To invoke remote service, you need define a service like:

@Service
public class HelloClient {

    @Inject(from=IRemoteServiceLoader.NAME)
    protected IHello _helloSvc;

    public String getHelloString(String title, String name) {
        return this._helloSvc.sayHello(name, title);
    }
}

The "IRemoteServiceLoader.NAME" is a string value which indicate the injected IHello service should be received from remote host, the framework will check remote service registration information and generate a IHello proxy to inject to the service. The the HelloClient can invoke the service like local service.

Version History

  • Featured

    • Support register service to Consul.
    • Service status can be monitored.
    • Support Docker image based development.
    • Full documentation.
    • Increase unit test coverage.
  • v0.4 - in working

    • Event support, decide using 3rd library or implement it self.
    • Behavior(actions) definition.
    • Event based behavior(actions) execution.
    • Support custom service parameter and return type.
  • v0.3

    • Using Netty to provide HTTP service
    • Generic Restful service based on consistent HTTP service API
    • A profile to indicate which service can be registered or not.
    • Asynchronous service invocation.
  • v0.2

    • Remote service injection which is interface based.
    • Generate remote service proxy based on specific interface.
    • Implement restful remote proxy.
    • Multiple restful services can be aggregated with a interface and can be exposed to a restful service.
  • v0.1

    • Enhance service class at build time and based on customized annotation.
    • Support local service injection.
    • Support Spring service injection.
    • Annotation based configuration.
    • A simple log service provider which is Logback based.
    • Embedded web server which is Jetty based.
    • Support a simple restful service register to embedded web service based on annotation.

uapi's People

Contributors

gitter-badger avatar minjing avatar waffle-iron avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

uapi's Issues

Service should support lifecycle

Some services use resources to achieve some functionality, for these services we need to provide some methods like onInit, onUnload to make these services can apply resources and free resources when system shut down.

Generated Service should be a pretty Class Name

Currently the generated service name construct by extended service class name plus a "_Generated" postfix, it is not good enough, the suggestion is:

  • Generate a MD5 code for service class file, so the MD5 code will keep same if the class does not change.
  • Extract the first 5 characters as a generated class postfix and connect with "_".

The framework can handle the lifecyle of the service

Normally the service has a lifecycle: resolved, satisfied, initialized, destroyed.

  • Resolved: the service is resolved, but all dependencies is not set, the service can't serve.
  • Satisfied: all dependents has been set to the service,
  • Initialized: the initialization method of the service has been invoked, the service can serve to outside.
  • Destroyed: the service has been destroyed.

Service Defintion

Define a service by Java ServiceLoader, the service be able to define its dependencies.

Try to Load External Service when Resolve the Dependency Failed

Currently load external services is in Repository.start method and it is invoked only once, the behavior is not good, since if some services are added after start method is invoked then the unresolved dependency can't be loaded by external service loader, it is better that load external service dynamically

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.