Pages

Showing posts with label Netty. Show all posts
Showing posts with label Netty. Show all posts

Saturday, September 6, 2014

Atlassian Lego Jira plugin development: simple multi-functional plugin with services (Lego,RaspberryPi, Netty)

   Not so long time ago I've been doing  small presentation about how to create various plugins into  the Alassian ecosystem, mainly Jira and Confluence. I want to share some step how to deal with plugin that aggregates more functionalities (CRUD Servlet with Services, Project Template and REST api). 
One of the issue here is the version of the Atlassian libraries you will use for your development. Reason is obvious, compatibility and another repositories. So let's take a look on maven descriptor file pom.xml. 
...

    
      jfrog
      http://repo.jfrog.org/artifactory/libs-releases
    
    
      atlassian-public
      https://maven.atlassian.com/repository/public
      
        true
        never
        warn
      
      
        true
        warn
      
    
  
...

    5.0.4
    6.1.7
    2.5.0
    3.0.0-m24
    2.7.1
    2.18
    

    4.3.5
    2.1

    
    1.0-SNAPSHOT
    
    4.11
    1.8.5

...
  The nice thing on the plugin development is testing of all parts during the process. Atlassian provides some testing libraries (ex. jira-tests or jira-func-tests) in additions with others (harmcrest matcher, mockito, junit etc...) 
Img.1.: heart of the plugin -> descriptor file -> atlasssian-plugin.xml
The most important of the plugins is the heart (Img.1.) represented by descriptor file. 

  
    ${project.description}
    ${project.version}
    
    images/pluginIcon.png
    images/pluginLogo.png
  
  

  
    The LEGO CRUD Issue Plugin
    /issuecrud
  

  
  
  

  
  
    Lego CRUD Resources
    com.atlassian.auiplugin:ajs
    com.atlassian.auiplugin:jquery

    
      
    

    

    
    
    

    atl.general
  

  
    com.example.plugins.tutorial.servlet.LegoBrickService
  

  
  
    Provides Lego Brick services.
  

  
  
    

It shows which technologies (Soy ~ Google Closure, Blue-prints, Velocity ...) we use inside the plugin and which parts of jira core services we employ to make the plugin work according what we are expecting from it:
Img.2. - add1.: Lego Project Template is INSIDE like Intel
1. Lego project template (Img.2., Img.3.)
2. Lego Issue tracker 
3. Lego REST API 
Img.3. - add1.: Lego Template is there with Customised workflows and Issues
Add1.:: From the descriptor file we can read that for the template we do use Soy file. Closures allows us to dynamically generates the web page content
{namespace JIRA.Templates.ProjectLegoTemplates.Lego}
...
{template .renderLegoProjectTemplateExplanation}
    {getText('lego.project.template.info.page.description')}


    ...
    
  • {getText('lego.project.template.reason.1')}
  • {getText('lego.project.template.reason.2')}
  • {getText('lego.project.template.reason.3')}
... {/template} ...
and together with all messages having stored in property files makes internationalisation process latter much more easier. The whole project workflow together with issues is defined by *.json file
{
    "issue-type-scheme":
    {
        "name": "lego.project.template.issuetype.scheme.name",
        "description": "lego.project.template.issuetype.scheme.description",
        "issue-types": [
            {
                "key": "issueType1",
                "name": "New Lego Feature",
                "description": "A new Lego JSON feature of the product, which has yet to be developed.",
                "icon": "/images/icons/newfeature.png",
                "workflow": "wf1"
            },
            ...

    },
    "workflow-scheme":
    {
        "name": "lego.project.template.workflow.scheme.name",
        "description": "lego.project.template.workflow.scheme.description",
        "default-workflow": "wf1",
        "workflows": [
            {
                "key": "wf1",
                "name": "lego.project.template.workflow.wf1.name",
                "workflow-bundle": "/wfb/Issue-Tracking-Workflow.jwb"
            },
            ...
...
and the project is hooked with the JIRA system by using Blueprints API. Specifically implementing the interface AddProjectHook with @Overriden methods validate and configure .  
...
public class LegoProjectHook implements AddProjectHook {
    ...
    @Override
    public ValidateResponse validate(final ValidateData validateData) {
       ...
    }

    @Override
    public ConfigureResponse configure(final ConfigureData configureData) {
       ...
    }
...

  The result looks pretty cool because now we have inside the JIRA official Lego Project with its own issues and flows how to solve them. We can also track whole development. 
Img.4.: Lego Project inside the JIRA 
Add2.:: Lego issue tracker. 
   For those who has experiences with Lego MindStorm EV3 Java/Scala development it's nothing new to get an issue. The tracker is represented by the simple servlet that handles 
Img.5.:: Lego Issue Tracker
GET and POST request and allows to share the issue with others (Img.5). 
Img.6.: Velocity templates for LegoIssueTracker
   For generating the Lego issue tracker front-end (Img.6.) we use Velocity server-side template language. 
In side every template file (edit.vm, list.vm or new.vm) is possible to employ JavaScript to make for example cross-domain JSONP calls and get information from another resources (in my case RaspberryPi powered by Netty)
example: new.vm or edit.vm
...
function getRaspData(){
  jQuery.ajax({
    url: 'IP_ADDRESS',
    dataType: 'JSONP',
    jsonpCallback: 'callback',
    type: 'GET',
    success: function (data) {
      ...
      jQuery('input[name="ip"]').val(data.ip);
    }
  });
}
...
AJS.$(document).ready(function() {
   jQuery('.button-rasp').click(function() {
      console.log('RASP PI');
      ...
      getRaspData();
   });
});
...
...
...edit.vm - Velocity template language ...
...
<h1> Edit Lego issue $issue.getKey()</h1> #if ($errors.size()>0) ...
Now we are ready, according to the atlassian descriptor file, to create the Servlet implementaiton:
public class IssueCRUD extends HttpServlet {
    ...
    private static final String PLUGIN_STORAGE_KEY = "com.example.plugins.tutorial.servlet.lego";
    private static final String NO_IP_MESSAGE = "No IP Setup";
    ...
    private IssueService issueService;
    private ProjectService projectService;
    private SearchService searchService;
    private UserManager userManager;
    private TemplateRenderer renderer;
    private LegoBrickService legoBrickService;
    private static final String LIST_BROWSER_TEMPLATE = "/templates/list.vm";
    private static final String NEW_BROWSER_TEMPLATE = "/templates/new.vm";
    ...
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ...
    }
    ...
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ...
        User user = getCurrentUser(req);
        ...
     }
 ... 
After short coding session we have prepared also LegoIssue sending functionality 
Img.7.:: send the 1st Lego Issue to the LEGO project
The REST API in JIRA is power by JAX-RS - Jersey. It's easy to expose. Let's move back to the Atlassian descriptor file and define the access path. The whole work is then strait forward in our example:Add3.:: Lego REST api 
@Path("/")
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public class RestLegoService {
…
   public RestLegoService(PluginSettingsFactory pluginSettingsFactory) {
        this.pluginSettingsFactory = pluginSettingsFactory;
    }
   @GET
   @Path("brick")
   public Response getLegoBrick() { 
   …
In the end we get appropriate JSON response by accessing the defined path. 

I hope this blog post helps in way to get a basic idea how to deal with Atlassian plugin development. In my case I don't want to use it as the reminder what I have done :)
Enjoy!
PS: I've used IntelliJ IDEA 13.x and SourceTree    
  

Friday, June 27, 2014

Spring4Netty without Web.XML configuration on Java 8 (JBoss WildFly and Tomcat 8) - part.5:: Application Servers and logging

  
img.1.: official log



  This part about selected application start normally, just by downloading both of them and setting them up in your favorite IDE (img.2.) which is in my case IntelliJ IDEA (img.1.)


img.2.: Application Serves bond with IDE
   So here we go, app servers inside (like the intel processor). What it good to point out already at the beginning is the servlet-api versions support. 

Don't try to run this example project (GiTHub repository) on Tomcat 6.x. Why ? It's because Tomcat 6.x supports servlet-api ver. 2.5, and as you can find in the parent pom.xml file, the version 3.x of servlet-api is required. It's because of features we have touched earlier  (part.4.) .

   Almost every project uses some logging framework, in project case we use Simple Logging  Facade (SLF4j) together with well known Log4j. I don't want to write a lot about application logging design it's the another story (this project is just hot setup of usage). 
   What I want to touch here is the topic "How to enable logging under JBoss WildFly per deployment for SLF4j" 
   It 's because by the default installation of WildFly it not allowed. You see actually any Logger output in your SystemOut or log file.  

Let's edit in following way the ../standalone.xml file that you can find in the WildFly directory
   ...
   
        
            
            <!-- IMPORTANT LINE --> 
            

            
                
                
                ...
                
                
            
            
        ...
        
   ...
   
   ...
The logging is not fully setup but important details are there so you can enjoy my project. 
s4netty project GiTHub repository



ps: Also I've not merged JUnit, Mockito  tests in case I didn't want to touch this topic in this blogpost. 

Spring4Netty without Web.XML configuration on Java 8 (JBoss WildFly and Tomcat 8) - part.4:: Base - Spring MVC without Web.xml usage 2

  
img.1.: s4netty-web deployment result

  The base web module s4netty-web is almost similar to  the previous worker module (s4netty-worker) from the perspective of the Spring MVC configuration. 

  The main difference is the Servlet Context setup. In the usage 1 (s4netty-worker) everything was defined by appropriate annotations. In the usage 2 (s4netty-web) the Servlet Context is defined in traditional XML way from perspective of servlet definition. 
   ...
   

   
     
     
   
   ...
  The WebApplicationContext is instantiated by XmlWebApplicationContext which (img.2.) extends AbstractRefreshableWebApplicationContext. Here we go deeper to all WebApplicationContext implementations which are supposed to instantiate themselves  according to the provided configuration over the interface. 
img.2.: s4netty-web module structure 
  The purpose of  XmlWebApplicationContext  class is to load WebApplicationContext from the XML configuration files.  
public class WebInitializer implements WebApplicationInitializer {
    ...
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        ...
        XmlWebApplicationContext ctx = new XmlWebApplicationContext();
        ctx.setConfigLocation("WEB-INF/spring/dispatcher-servlet.xml");
        ctx.setServletContext(servletContext);
        ...

  What was also earlier only briefly touched (part1:: img.0.) is the ability of s4netty-web module to communicate with s4netty-worker  module utilising JSON serialisation/deserialisation over the service and pre-defined port P.

  The s4netty-web module uses instantiation of the RestTemplate which simplifies communication with HTTP server, its synchronous and it enforces RESTful principles, what is obvious from it name RestTemplate ;), but honestly it's pretty handy to use. 
@Controller
@RequestMapping("/")
public class MainController {
    ...
    RestTemplate restTemplate = new RestTemplate();

    @RequestMapping(method = RequestMethod.GET)
    public String printWelcome(ModelMap model) {
    ... 
  Let's ask s4netty-worker module for the car list using newly instantiated RestTemplate
    ...
   private List getSimpleCarList(){
        List result = new ArrayList<>();
        try{
            result = restTemplate.getForObject(S4_NETTY_WORKER_LINK, List.class);
            logger.debug("getSimpleCarList result= " + result);
        }catch (HttpClientErrorException e){
            logger.error("getSimpleCarList jsonCarList e= " + e);
        }
        return result;
   }
   ...

  Now we have ready two deployable war files and we can take a look at the result. But before we do so it's fair to mention why such configuration works.  The reason is that we do use for
 registering servlets in both cases  
   ...
   import javax.servlet.ServletRegistration.Dynamic
   ...

interface which uses one of addServlet()  methods into ServletContext. The interface is the part of javax.servlet-api imported previously by Maven into the project. 
  ...
  
        javax.servlet
        javax.servlet-api
        3.0.1
        provided
  
  ...
After this final hit we do know all and we can start with deployment on application servers (JBoss WildFly & Tomcat 8 were selected).
Let's make it in the Next part (Click Next) 

s4netty project GiTHub repository

  

Thursday, June 26, 2014

Spring4Netty without Web.XML configuration on Java 8 (JBoss WildFly and Tomcat 8) - part.3:: Worker - Spring MVC without Web.xml usage 1

  

  Now we are entering the last stage in case of s4netty-worker.  Although we have already enabled Netty usage under spring ecosystem, we still want to provide some simple web (Spring MVC) for this module to see the output from the Netty JSON service.  


s4netty-worker - spring mvc output
img.1.: Spring MVC output from s4netty-worker

  I won't go into the details how to build up the basic Spring MVC project because it's easy to find out by our friend google. What is interesting is how to not use web.xml (Deployment Descriptor Element which determinates the urls mapping to appropriate servlets ) definition alias get some freedom for Java web applications. In case of s4netty-worker we do almost everything over annotations, only beans will be defined in separate app-worker-config.xml file (viz. img.2).  


img.2.: s4netty-worker module structure 

  Before we initiate web application itself by WorkerWebInitializer, that implements WebApplicationInitializer, we need to do some configuration here. (ps. WebApplicationInitializer allows us to configure servlets, filters and etc. by @Override onStatrup method)
public class WorkerWebInitializer implements WebApplicationInitializer {
   ...
   @Override
   public void onStartup(ServletContext servletContext) throws ServletException {
       AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
       ctx.register(WorkerWebConfig.class);
       ctx.setConfigLocation("spring/app-worker-config.xml");
   ...
without such configuration our WorkerWebInitializer is useless because after WebApplicationContext instantiation Spring looks for Spring configuration files annotated by @Configuration annotation. For this purpose we create WorkerWebConfig class. 


@Configuration
@ComponentScan("com.miko.s4netty")
@EnableWebMvc
public class WorkerWebConfig {
   ...
   @Bean
   public UrlBasedViewResolver setupViewResolver() {
   ...

in WorkerWebConfig class we tell to the Spring where it should look for the rest of components (example: classes annotated by @Controller). By using @EnableWebMvc we import  the DelegatingWebMvcConfiguration which delegates us to all beans reliable for WebMvcConfigurer and our customisation.  At the end the method setupViewResolver allows us to briefly solve symbolic link name to the URL. Pretty cool, isn't it ?

  The one of the impact is that we can store our favorite ;) *.jsp pages in the appropriate directory (img.2.)

  Now we have ready s4netty-worker web output with appropriate Beans initialisation, which is done by ServletContext configuration definition located in the file spring/app-worker-config.xml

  

  
    
  
   And finally our result looks according to the img.1. mentioned at the beginning of this part. 
The big moment is here because we are moving to the stage 2 (s4netty-web).
The next part (Click Next) 

s4netty project GiTHub repository 
  

Spring4Netty without Web.XML configuration on Java 8 (JBoss WildFly and Tomcat 8) - part.2::netty and JSON

  

  In the introduction (part.1). we've pictured out the basic idea of the project  abstraction(car exchange;). In this part we are going to configure Netty as the part of maven spring module (s4netty-worker). 

  Let's draw the agenda that allows us to start netty server under the spring ecosystem:
  1. initiate serverBootstrap object and configure the Netty server from properties file (worker-server.properties).
  2. configure the group, channel, handler and some channel options (ps: keep alive signal has been ignored in this project)
  3. Channel initialisation  
  4. Netty JSON service response
  5. Netty JSON request handling
  Let's begin and configure WorkerNettyServer which contains the instance of the serverBootstrap bean (add.1.). ServerBootstrap definition can be found in WorkerNettyConfig class.
@Bean(name = "serverBootstrap")
public ServerBootstrap bootstrap() {
All necessary  properties for WorkerNettyConfig class used by serverBoostrap (add.1.) bean initialisation are taken from the config the file (worker-server.properties) 
@Configuration
@ComponentScan("com.miko.s4netty")
@PropertySource("classpath:worker-server.properties")
public class WorkerNettyConfig {
  To make possible reading from the *.properties file   
@Value("${tcp.port}")
private int tcpPort;
we need to have access to the current Spring Context. This goal we achieve by using property sources place holder :
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
   return new PropertySourcesPlaceholderConfigurer();
}
Now WorkerNettyConfig knows all values for its initiation 
@Bean(name = "serverBootstrap")
public ServerBootstrap bootstrap() {
   ServerBootstrap b = new ServerBootstrap();
After all those configuration steps, we get access, inside the WorkerNettyServer class, to the bean "serverBootstrap" by using Qualifier annotation for candidate Bean serverBootstrap (add.2.). 
@Component
public class WorkerNettyServer {
    ...
    @Autowired
    @Qualifier("serverBootstrap")
    private ServerBootstrap serverBootstrap;
    ...
and we can have quickly assign all serverBootstrap properties (add.2.) 
@Bean(name = "serverBootstrap")
public ServerBootstrap bootstrap() {
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup(), workerGroup())
    .channel(NioServerSocketChannel.class)
    .childHandler(workerInitializer);
  So move forward and initiate the Channel and it's pipeline in the WorkerInitializer class (add.3.). Of course all according to our "master plan" to have JSON service listening on the specified port P and exchanging car list with base.
  In this case we need totell Netty how it should deal with such type of the request by utilising HttpServerCodec (add.4.). 
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(workerProviderHandler);
  Currently it looks like JSON service  is listening on the port P and everything is almost ready to go. Well not exactly, there is still a some work do. 
  One good question could be about some missing definition :) oh, yes, where is 
workerProviderHandler ? (add.5.)  and here we go.
@Component
@ChannelHandler.Sharable
@Qualifier("workerProviderHandler")
public class WorkerProviderHandler extends ChannelInboundHandlerAdapter {
  ...
  @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof HttpRequest) {
            HttpRequest req = (HttpRequest) msg; 
  ...
  The workerProviderHandler is the extension of ChannelInboundHandlerAdapter and it handles our request and provides the JSON response to the requestor (s4netty-web). 
The request itself consists from results provided by spring service. 
...
@Autowired
SimpleCarService simpleCarService;
...
Gson library has been used to serialise and deserialise POJO objects.

After defining handler and assigning to the pipeline we are done with Spring-Netty Configuration and ready to define module (s4netty-worker) Spring MVC without Web.xml usage. 
Sure, in the next part (Click Next) 

s4netty project GiTHub repository




Spring4Netty without Web.XML configuration on Java 8 (JBoss WildFly and Tomcat 8) - part.1::introduction

  
  Although I'm working with Netty for while ( in different scenarios ;) ,  I've not found so much examples how to use Netty 4.x together with Spring Framework 4.x. Honestly I've found mostly some pieces of the whole solution (maybe I was not search so much around). 
  My following project shows how to make it  run. Another purpose of it is to present Spring 4 configuration without web.xml.

  My idea at the beginning was that this blog post will be just only small description how to. Pretty soon I realised that there is no chance to sum everything up into one blog post. I'd rather split everything into smaller parts than long fuzzy text (hopefully this text won't be fuzzy :). So I've separated everything  and parts could be accessed individually if  it's needed.  

The project is also available over my GiTHub repository .


img.0.: s4netty results (s4netty-web, s4netty-worker and JSON)


agenda:

  1. Configure Netty as service provider (s4netty-worker) 
  2. Configure s4netty-worker Spring MVC without Web.xml usage 1
  3. Configure Spring MVC without web.xml (s4netty-web) usage 2
  4. Run everything on JBoss Wildfly or Tomcat 8 with logging
servers: 
  1. Tomcat 8
  2. JBoss WildFly

development IDE: IntelliJ IDEA 13.x
other technologies: JRebel 6.x Experimental 
building tool: Maven 3.2.x
libraries: see the maven pom.xml - the parent module

Introduction: 
  The basic abstraction behind the application is exchanging JSON object between web spring MVC BASE (s4netty-web) and s4netty WORKER (s4netty-worker) (img.1.). The object exchange is done over defined port P.  For this purpose JSON has been used as the type of object serialisation. 
img.1.: s4netty app abstraction
  Both Spring-Base (s4netty-web) and Netty-Worker (s4netty-worker) modules use Spring MVC Framework with different type of WebApplication context initialisation. Aside Netty-Worker uses Netty (asynchronous event-driven framework) to open the Port P to provide the result of the spring service to the Spring-Base (s4netty-web). Spring-Base uses restTemplate for communication with  Netty-Worker. 

  So let's start to exchanging cars and move to the PART 2. (click).