Img.1. - Let's turn on the LegoBrick again and make remote project based on Gradle
The previous post about Lego MindStorm EV3 has been focused on its installation. I've touched how to install JavaJDK setup Wifi on LegoBrick + small sample "hello world" project. This blog post is about setting up little more advanced project. The simple HelloWorldGradle Remote project uses:
The legoBrick, connected to the WiFi, is possible to access remotely without problem using Java Remote Method Invocation, shortly RMI.
RemoteEV3 ev3Brick = new RemoteEV3(EV3BRICK_IP);
ev3Brick.setDefault();
Before we start working on the sample source code we create Gradle project. We can randomly choose the project as HelloWorldGradle. Important is to setup Gradle property file "build.gradle" correctly
jar library "ev3classes" is very important! This library creates the gateway into the lego hardware by using RMI because EV3 acts as the RMI Registry. You need to create it by yourself.
This library can be created by maven with usage of maven-assembly-plugin. The final *.jar file can then easily imported into the local maven cache. Now we are ready to remotely access our Lego MindStorm robot and in our case let him to play some short song.
RemoteEV3 ev3Brick = new RemoteEV3(EV3BRICK_IP);
ev3Brick.setDefault();
Audio soundProcessor = ev3Brick.getAudio();
List tones = new ArrayList<>(asList(0,1,2,3,4,5));
tones.forEach(tone -> {
soundProcessor.systemSound(tone);
});
The sample LejOS remote project HelloWorldGradle is available here (GITHub). Enjoy !
I do believe that the default lego software for EV3 is pretty awesome ;) but my interest belongs to java virtual machine which implies installation of LeJOS.
Let's prepare LeJOS SD card for the mission: 1. from the manual: card must be bigger than 2GB and FAT32 2. unpack leJOS file -> go to the folder -> copy the lejosimage.zip file to the SD Card 3. unpack lejosimage.zip 4. copy downloaded Java SE file to the CD-Card (SD Card root) 5. put SD-CARD to the Lego Brick and finally startup
To work with LeJOS comfortably is required to have WiFi connection via dongle (Img.2.). Then is possible to deploy directly for the IDE (IntelliJ IDEA 13.x in my case) to Lego Brick.
Img.2.:: supported NetGear N150 USB Wireless Adapter
Prepare Wifi Connection: 1. Boot Brick and select Control -> Wifi -> select network with WPA2
Img.3.:set the wifi password
2. Create a sample maven program (how to will be the topic of the next blog post)
Img.4.: favorite IDE IntelliJ IDEA 13.x with Maven Lego Project inside and upload command
for those who want to use maven directly for the deployment they need to configure maven-antrun-plugin So now we have Lego Mindstorm EV3 ready for read development and sensors usage...
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 projectGiTHub repository
ps: Also I've not merged JUnit, Mockito tests in case I didn't want to touch this topic in this blogpost.
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-webmodule 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
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.
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 projectGiTHub repository
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.
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-workerweb 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 projectGiTHub repository
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:
initiate serverBootstrap object and configure the Netty server from properties file (worker-server.properties).
configure the group, channel, handler and some channel options (ps: keep alive signal has been ignored in this project)
Channel initialisation
Netty JSON service response
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 SpringContext. 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 BeanserverBootstrap (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.).
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.
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 projectGiTHub repository
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.
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 WebApplicationcontext 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).