Monthly Archives: December 2015

Always use email as username

Don’t let your user input a "username" while registering.   It’s totally unnecessary.  And it can be awkward when user logins with an Open ID, such as Google or Facebook.  What will be the user name in this case? 

If a user registers on your site, just use their email as username.  It will make registration simpler.

If the user logins with an Facebook account,  you can use "facebook:some@some.com" as the user name. 

Best Practice of showing uml diagrams on github: plantuml + eclipse plugin + maven plugin

Note:  This post is only for laze developers who wants to get things done in a "coding" way. 

You can draw your UML diagram with any kind of UML drawing tool, export it as an image, and save it on github repository. On your github README.md you can then reference this file. 

The problem is too many window switch and too many mouse clicking. 

My solution to this,

1. Use plantuml to generate UML diagrams with plain-text directives.

2. Use plantuml eclipse plugin to see the diagram in real time.

3. Use plantuml’s maven plugin to output PNG files to your code repository, by running a maven command. 

How to enable log4j when doing spring-based integration test?

Just put a log4j.xml on test’s class path and log4j will be activated.

However, you may hate to have 2 "log4j.xml" in your eclipse. You want the log4j config for testing to be called log4j-test.xml. In that case, do the following:

//create your own runner, withen which load log4j
public class MySpringJunit4ClassRunner extends SpringJUnit4ClassRunner {
	static {
		try {
			Log4jConfigurer.initLogging("classpath:log4j-test.xml");
		} catch (FileNotFoundException ex) {
			System.err.println("Cannot Initialize log4j");
			ex.printStackTrace();
		}
	}

	public PalaSpringJunit4ClassRunner(Class clazz)
			throws InitializationError {
		super(clazz);
	}
}
//And run with your own runner
@RunWith(MySpringJunit4ClassRunner.class)
public class SomeITCase {
...

Jersey Client: What if the server side doesn’t return JSON ContentType when it is supposed to?

Your server says it will return JSON string as response, but the ContentType header it sends is not "application/json" but "text/html". What will happen?  

Your client will see an exception saying "A message body reader for … was not found" . 

What you need to do is to have your own "provider" and let it take whatever content type. 

public class MyJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider {

	/**
	 * always return true.  
	 */
	@Override
	protected boolean hasMatchingMediaType(MediaType mediaType) {
		return true;
	}
}
//register it with your Jersey client
		restClient = ClientBuilder.newBuilder()
				.register(MyJacksonJaxbJsonProvider.class).build();

Design for Error Response in Web Services

The server side should send error code and error message.  Is that all? 

Yes, basically it will work, but not perfect yet.

What you need to do:

1. Differentiate known, user-readable errors from unknown, developer-readable errors.  

2. Send an error ID to client side when there is an unknown error, with which the client developer can help server side developer locate the error’s detailed information, thus more easily troubleshoot the problem. 

An example in Java:

public abstract class Err {

	protected String errCode;
	...
public class KnownErr extends RestErr {
 
	private String errMsg;
	...
public class UnknownErr extends Err {

	private String devErrMsg;
	//the error ticket
	private String exceptionId;

	...
//You must have had a global exception handler. Do something like, 

		String exceptionId = Thread.currentThread().getName() + "-"
				+ DateFormatUtils.format(new Date(), "yyyyMMddHHmmsSSS") + "-"
				+ RandomStringUtils.randomAlphanumeric(5);

		// first log it
		logger.error("Unknown Server Error. Exception Id = "
				+ exceptionId, ex);

		UnknownErr err = new UnknownErr(someErrCode, exceptionNameAsDevErrMsg, exceptionId);

		sendResponse(err); 

		...

JavaFX: how to let one FXML include another

How to let one fxml include another, e.g. let every scene has a "header" ?

 

  

Note you have to set "fx:id=…"

There must be a controller for the included fxml file. Let’s call it HeaderController

   

	


  
public class HeaderController {


	@FXML
	private Text errorText;
	... 
  

Include the HeaderController in your controller

 public class LoginController {
	//the variable has to start with "header", because during the fxml inclusion you have set its id as "header", i.e., fx:id="header" 
	@FXML
	private HeaderController headerController; 
	...
	public void someMethod(){
		headerController.setErrorText("Something is wrong");        
	...  

Code Snippet: Validate the size of uploaded file on server side

One way is to write the input stream to server side as a file and then validate that file.   However, the uploading has happened. It will not prevent a user from uploading a huge file and taking up server side’s the bandwidth and hard disk.   

So we must do validation while reading the input stream and abort the uploading right away when size limit is reached. 

	/**
	 * read an input stream to a byte array. Return an exception if the stream
	 * is too long or too short. If it is too long, an exception will be thrown
	 * and the reading will be aborted
	 * 
	 * @param in
	 * @param minSize
	 * @param maxSize
	 * @return
	 * @throws InputTooShortException
	 * @throws InputTooLongException
	 * @throws IOException
	 */
	public static byte[] toByteArrayAndValidSize(InputStream in, long minSize,
			long maxSize) throws InputTooShortException, InputTooLongException,
			IOException {

		@SuppressWarnings("resource")
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		byte[] buffer = new byte[4096];

		long count = 0;
		int n = 0;
		while (-1 != (n = in.read(buffer))) {
			output.write(buffer, 0, n);
			count += n;
			if (count > maxSize) {
				throw new InputTooLongException();
			}
		}

		if (count < minSize) {
			throw new InputTooShortException();
		}

		return output.toByteArray();

	}

P.S.: inputStream.available() is not reliable. The javadoc says: "Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream."