posted in JavaScript 

Today my workmate hit an issue that v-if didn't work for him.
It turned out that Vue.js can't watch the property that you do not define at the beginning.

Root Cause

It's not only relative to v-if. It impact all functions that used two-way data binding.

On below demo, we have two section that both of them hope to change content by button clicking. Section 1 works good but section 2 didn't.

It's because section2 object(in js) doesn't define content property.
So after Vue runs up, the new property that you add afterward can't be watched by Vue. And then you will fine your change will not reflect to web page even if you change the value of the property.

In this demo, I tried to change the content of section 2 but it didn't work. In my workmate's case, it change the value of a property but v-if was not triggered.

Live Demo: https://jsfiddle.net/Lawrence/7eq3y5uv/

Look Deeper

When Vue.js starts, it will convert all data into observable. The key is how Vue.js do that here.

Vue.js will bind Watcher on each properties of an object by defining set method using Object.defineProperty. Therefore Vue.js can get updated if you change the value.

Apparently, if you don't define an property for an object at the beginning, Vue.js can't watch it.

这是一系列来自阿里的 ElasticSearch 的原理剖析文章。文章质量优秀,干货十足。

一是 ES 是非常流行的分布式搜索引擎,不管是日常运维还是生产环境都非常实用。
二是 ES 也是一个典型的分布式系统。分布式系统避不开的集群、服务发现、Master 选举等话题在此系列文章中都有涉及。如果想了解如何开发一个高可用,可伸缩的分布式系统,ES 也是一个很好的例子。

Elasticsearch分布式一致性原理剖析(一)-节点篇

Elasticsearch分布式一致性原理剖析(二)-Meta篇

Elasticsearch分布式一致性原理剖析(三)-Data篇

posted in Java 

It's an important feature that JVM provided and I'm so surprised that I used it at the first time today.

How to enable remote debugging

To enable it, you will just need to add below JVM arguments in command line:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

Then you can use your debugger to attach to remote JVM.

suspend is quite useful argument here. If suspend is y, JVM will suspend before main class is loaded until debugger attach to it. n otherwise.

So set suspend to y if you need to debug application initialization phase.

Check Official Document for detailed introduction

Remote Debugging in IntelliJ IDEA

I believe all IDEs have that function to debug Java application remotely. I use IntelliJ here for demonstration.

Remote Debug Configuration in IntelliJ
Add a new configuration under Remote category, you will see IntelliJ provides command line arguments for you. That's exactly what I show in previous section.

Change the host to your server's url, and launch your application with remote debug arguments, then you can debug as what you did on debugging local application.

DO NOT REMOTE DEBUG YOUR PRODUCTION APPLICATION

I confused for so long that what Cherry-Pick is. And today I got some times to learn it.

What Cherry-Pick can do

Cherry-Pick can pick some commits from other branch, merge into your current working branch.

Use Cases

  • If you're working on a dev branch. You have not yet complete your task but there are change committed. And now you need to merge part of you work into master for some reason but you don't want to merge the dev branch into master. And now you can cherry pick the commits that just you need, and merge them into master.

  • If you merge your commit into wrong branch. And now you need to merge you change into master. You can cherry pick you change and merge into master branch. Then revert your change into that wrong branch.

Many years ago I have heard that docker is an amazing stuff to manage the build, deployment and service life cycle. But at that time, there were also some bad news on security that prevented me from trying it.

And today I finally found a day to play with it. The result is, Docker is a amazing thing to manage my service. It exactly fix my problem that this years I'm trying to improve and contributing to my business.

Service Isolation

Docker will create individual VM to serve each services. Most of OS resource are isolated so that dev doesn't need to care about the system resource(at least less care about it). Also we can keep clean codebase without system specified logic.

In my company we run services in several hosts shared to different teams. It's not a frequent case but also annoying that different services will try to use same port, will try to user different JDK version on the path, will need to change same environment variable.

Some service change those share resource dynamically and leads to random failures/issues that hard to locate.

In this scenario, Docker may be one of solutions.

Unified Stander to Deploy Services

DevOps requires less manual work on our build, test, release process. All stuffs should be able to automatically proceed. It absolutely is a good idea. When we serve our system in a large scale and cooperate with so much teams, more manual work we need, much risk we introduce. No one want to stick in fire-fight at mid night. And Docker provide a unified stander to manage service's resource and environment. That means, we are easily to write automatic process for build, for test and for deployment.

The company I work on has its own solution to manage resource and do things automatically. We have huge set of scripts and softwares to setup dev environment, setup build agents for TeamCity and Jenkins, to deploy application, to verify or monitor the function we provide.
They are awesome, they have provided huge value to business. But it's customized. New engineers are hard to understand the ecosystem.

I think Docker is good way to reduce the learning cost because of aligned style to manage resource

Scalability

It's the most well-known feature for Docker, no need more words to admire it.

posted in Java 

Today I'm trying to make an endpoint accessible in different paths. Such as I can go to http://localhost/ and http://localhost/hello for a same hello message.

I do got some solutions.

I'm using Jersey over Jetty. But whether or not you're using Jetty servlet or writing Jersey Resource, I think you will get some ideas.

Ps: I copy the code from my GitLab Snippets and will keep it update. So If you find something wrong, pls comment in GitLab

Using the regular expression in Jersey Resource

https://gitlab.com/snippets/1676612

package me.imlc.example.jetty.multiplehandler;

import com.sun.jersey.spi.container.servlet.ServletContainer;
import me.imlc.example.jetty.multplehandler.HelloResource;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.Objects;

import static org.junit.Assert.assertEquals;

public class RegexpResourceTest {

    private static Server server;
    private static CloseableHttpClient client = HttpClients.createDefault();

    @BeforeClass
    public static void beforeAll() throws Exception {
        ResourceConfig rc = new ResourceConfig(RegexpResource.class);

        ServletHolder holder = new ServletHolder(new ServletContainer(rc));

        server = new Server(8080);

        ServletContextHandler contextHandler = new ServletContextHandler(server, "/*");
        contextHandler.addServlet(holder, "/*");

        server.start();
    }


    @Test
    public void canAccessByRootPath() throws Exception {
        HttpGet get = new HttpGet("http://localhost:8080/hello");
        String content = EntityUtils.toString(client.execute(get).getEntity());
        assertEquals(content, "Hello, Lynn.");
    }

    @Test
    public void canAccessByServicePath() throws Exception {
        HttpGet get = new HttpGet("http://localhost:8080/service/hello");
        String content = EntityUtils.toString(client.execute(get).getEntity());
        assertEquals(content, "Hello, Lynn.");
    }

    @AfterClass
    public static void afterAll() throws Exception {
        if(Objects.nonNull(server)) server.stop();
        if(Objects.nonNull(client)) client.close();
    }

    @Path("/{a:(.*)|service}")
    public static class RegexpResource {
        @GET
        @Produces(MediaType.TEXT_PLAIN)
        public String hello() {
            return "Hello, Lynn.";
        }
    }
}

Specify multiple paths for one servlet

https://gitlab.com/snippets/1676613

package me.imlc.example.jetty.multiplehandler;

import com.sun.jersey.spi.container.servlet.ServletContainer;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.Objects;

import static org.junit.Assert.assertEquals;

public class MultipleServletTest {

    private static Server server;
    private static CloseableHttpClient client = HttpClients.createDefault();

    @BeforeClass
    public static void beforeAll() throws Exception {
        ResourceConfig rc = new ResourceConfig(RegexpResourceTest.RegexpResource.class);

        ServletHolder holder = new ServletHolder(new ServletContainer(rc));

        server = new Server(8080);

        ServletContextHandler contextHandler = new ServletContextHandler(server, "/*");
        contextHandler.addServlet(holder, "/*");
        contextHandler.addServlet(holder, "/service/*");

        server.start();
    }

    @Test
    public void canAccessByRootPath() throws Exception {
        HttpGet get = new HttpGet("http://localhost:8080/hello");
        String content = EntityUtils.toString(client.execute(get).getEntity());
        assertEquals(content, "Hello, Lynn.");
    }

    @Test
    public void canAccessByServicePath() throws Exception {
        HttpGet get = new HttpGet("http://localhost:8080/service/hello");
        String content = EntityUtils.toString(client.execute(get).getEntity());
        assertEquals(content, "Hello, Lynn.");
    }

    @AfterClass
    public static void afterAll() throws Exception {
        if(Objects.nonNull(server)) server.stop();
        if(Objects.nonNull(client)) client.close();
    }

    @Path("/hello")
    public static class MultipleServletResource {
        @GET
        @Produces(MediaType.TEXT_PLAIN)
        public String hello() {
            return "Hello, Lynn.";
        }
    }
}

Serve one servlet in different context handler

https://gitlab.com/snippets/1676615

package me.imlc.example.jetty.multiplehandler;

import com.sun.jersey.spi.container.servlet.ServletContainer;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.Objects;

import org.eclipse.jetty.server.handler.ContextHandlerCollection;

import static org.junit.Assert.assertEquals;

public class MultipleContextHandlerTest {
    private static Server server;
    private static CloseableHttpClient client = HttpClients.createDefault();

    @BeforeClass
    public static void beforeAll() throws Exception {
        ResourceConfig rc = new ResourceConfig(MultipleContextHandlerResource.class);

        ServletHolder holder = new ServletHolder(new ServletContainer(rc));

        server = new Server(8080);

        ServletContextHandler rootContext = new ServletContextHandler(server, "/*");
        rootContext.addServlet(holder, "/*");

        ServletContextHandler serviceContext = new ServletContextHandler(server, "/service/*");
        serviceContext.addServlet(holder, "/*");

        ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
        contextHandlerCollection.setHandlers(new Handler[]{
                rootContext, serviceContext
        });

        server.setHandler(contextHandlerCollection);

        server.start();
    }

    @Test
    public void canAccessByRootPath() throws Exception {
        HttpGet get = new HttpGet("http://localhost:8080/hello");
        String content = EntityUtils.toString(client.execute(get).getEntity());
        assertEquals(content, "Hello, Lynn.");
    }

    @Test
    public void canAccessByServicePath() throws Exception {
        HttpGet get = new HttpGet("http://localhost:8080/service/hello");
        String content = EntityUtils.toString(client.execute(get).getEntity());
        assertEquals(content, "Hello, Lynn.");
    }

    @AfterClass
    public static void afterAll() throws Exception {
        if(Objects.nonNull(server)) server.stop();
        if(Objects.nonNull(client)) client.close();
    }

    @Path("/hello")
    public static class MultipleContextHandlerResource {
        @GET
        @Produces(MediaType.TEXT_PLAIN)
        public String hello() {
            return "Hello, Lynn.";
        }
    }
}

posted in Java 

This page show you why we need to disable TRACE HTTP method for security reason. And provide a sample project to show you how to disable TRACE in embedded Jetty.

Why we need to disable TRACE method

Allowing TRACE method will leads to Cross-Site Tracking (a.k.a XST) problem. XST was found in 2003. It’s a very old topic and I can’t get any new discussion after searched in Google. But it’s good to disable TRACE for our server to avoid any redundant endpoint exposes to the danger world.

Avoid XST Attack

As we all know, server will echo back all information when it receive TRACE request. “All information” means the cookies, the credential data and the server version etc. When user is visiting a malicious website, a hacker can read malicious data by calling a cross-site TRACE request.

Limit Information Expose to the World

In the other case, we run an API server which user will not access by browser directly. It’s good practice to limit the information expose to the external world. Information like version may tell others which issue is ok to use to hack. If we don’t need TRACE (at lease in production environment), so disable it.

How to disable TRACE in Embedded Jetty

By default Jetty enables TRACE and we need to disable it manually.
This GitHub project shows you how to disable TRACE for embedded Jetty.

private Handler wrapWithSecurityHandler(Handler h){
        Constraint disableTraceConstraint = new Constraint();
        disableTraceConstraint.setName("Disable TRACE");
        disableTraceConstraint.setAuthenticate(true);

        ConstraintMapping mapping = new ConstraintMapping();
        mapping.setConstraint(disableTraceConstraint);
        mapping.setMethod("TRACE");
        mapping.setPathSpec("/");

        // omissionConstraint is to fix the warning log ""null has uncovered http methods for path: /
        // No impact to disable TRACE if you do not add this constraint
        // But if you're using the monitoring tool like Geneos, and your component requires keep production monitoring all green,
        // You can try to add this omissionConstraint to fix the warning Jetty prints.
        Constraint omissionConstraint = new Constraint();
        ConstraintMapping omissionMapping = new ConstraintMapping();
        omissionMapping.setConstraint(omissionConstraint);
        omissionMapping.setMethod("*");
        omissionMapping.setPathSpec("/");


        ConstraintSecurityHandler handler = new ConstraintSecurityHandler();
        handler.addConstraintMapping(mapping);
        handler.addConstraintMapping(omissionMapping);
        handler.setHandler(h);
        return handler;
    }

Also notice that I wrote omissionConstraint, applied to all method to fix a warning Jetty prints:
null has uncovered http methods for path: /

If you’r not required to keep production monitoring all green, you can delete this redundant constraint and accept this warning.

References

[1] CROSS-SITE TRACING (XST) - THE NEW TECHNIQUES AND EMERGING THREATS TO BYPASS CURRENT WEB SECURITY MEASURES USING TRACE AND XSS - Jeremiah Grossman
[2] Cross Site Tracing - OWASP
[3] spring - Java embedded jetty is accepting HTTP TRACE method - Stack Overflow

posted in Others 

在中国,使用 Windows 的远程桌面服务有两个困难。

  1. 官方的 Remote Desktop Client on Mac 不在中国销售。
  2. 家庭版的 Windows 10 不包含远程桌面服务。

解决方法是两个都找第三方解决方案。

  1. 使用 Parallels Client 代替 Remote Desktop Client on Mac
  2. 适用 rdpwrap 提供远程桌面服务

安装 Parallels Client

Parallels Client: https://itunes.apple.com/us/app/parallels-client/id600925318?mt=12

或者需要付费但是一样更好功能更加强大的 Parallels Access:
http://www.parallels.com/cn/products/access/

安装 rdpwrap

GitHub: https://github.com/stascorp/rdpwrap

rdpwrap 是在家庭版 Windows 上提供远程桌买服务的一个开源项目。支持从 Windows Vista 到 Windows 10 系统。安装和使用说明请到 GitHub 主页查看。

posted in Angular 

It's very easy to make a mistake on Angular2 router. After refresh the page, the page to be routed to can not load successfully. Chrome console tell me that browser failed to load css resources as the path of resources is incorrect.

The solution is that put the <base href="/"/> directly under the title tag.