Making your scrips chkconfig aware

If you want to have your scripts run at startup and shutdown, there is a specific way of doing it using chkconfig (or /sbin/chkconfig).

The first thing to do is to get to know about runlevels. Run levels informally define the state to which your system is booting up to. Runlevel 5 in Fedora/RedHat/CentOS is the default and means Multi-user with X. Runlevel 1 typically means single user mode, Runlevel 3 is Multi-user mode without X. There are 7 runlevels, 0 through 6. The file /etc/inittab tells you the run level that your system boots up to by default.

Firstly you need to know the runlevels in which you need to run your startup scripts. Typically you’d be running your scripts in runlevel 3,4,5.

The first thing you need to add to your script is the comment

#chkconfig 345 98 02
#description: This is what my script does.

–The first set of numbers after chkconfig are the runlevels you want your script to run at startup.
–The second number is the priority of the script at start time i.e. 98 in this case. It means that your script will run after all scripts with priority less than 98 have already run.
–The third number is the priority of the script at shutdown i.e. 02 in this case.

When you add your script using the command chkconfig –add , 7 symlinks are created. Firstly the symlinks prefixed with S are placed in /etc/rc.d where runlevel are the levels you specified that your script should run at startup. Then in the remaining /etc/rc.d, symlinks prefixed with K are created.

Parse SDK in swift

When I was a newbie to swift, I spent a lot of hours getting this working.

Setup:  Xcode 6+, Parse SDK 1.6.2+, iOS 8+

Setting up Parse SDK in Xcode

  1. Create a new account at Parse.com
  2. Create a new Application
    parse-swift1
  3. Once your app is set up, Parse will provide you your keys. Note these keys and keep them safe
    parse-swift-2
  4. From the Downloads section of Parse.com, download the SDK

Set up your Xcode project

  1.  Create a new Xcode project and remember to select the Language as Swift
  2. Once the Application is created, click on your Project and go to “Build Phrases”.
    In the List “Link Binary With Libraries” you will have to add these Frameworks to use Parse.parse-swift-3AudioToolbox.framework
    CFNetwork.framework
    CoreGraphics.framework
    CoreLocation.framework
    libz.dylib
    MobileCoreServices.framework
    QuartzCore.framework
    Security.framework
    StoreKit.framework
    SystemConfiguration.framework
    libsqlite3.dylib
  3. Now drag the Parse.framework you downloaded before into your Xcode Project. Remember to check “Copy Items if needed” when you bring in the framework file

Make Parse SDK useable in Swift

Parse SDK is written in Objective-C. In order to use Objective C code in a swift project, you need to link the Objective-C header files using a special Bridging file. You can make Xcode do the work of setting up an empty bridging file.

  1. Create a new File (File -> New -> File) of type Objective-C File.
  2. You can use any name for this file. I am going to call it Dummy.m. We are not going to use this file. However, this will make Xcode ask you to create the bridging file
    parse-swoft-4
  3. Select yes. Xcode will add 2 files to your project – Dummy.m and the Bridging file. Lets call it BridgingHeader.h
  4. Add the following to your BridgingHeader.h
    #import <Parse/Parse.h>

 

Using Apache HTTPClient 4.x for MultiPart uploads with Jersey 1.x Server

You can easily find a lot of articles on the web describing the process to use Jersey client with a Jersey 1.x Server to do multi-part uploads. However, when trying to use Apache HTTP client, it uncovers a bug in jersey causing a NullPointerException – https://java.net/jira/browse/JERSEY-1658

SEVERE: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
java.lang.NullPointerException
    at     com.sun.jersey.multipart.impl.MultiPartReaderClientSide.unquoteMediaTypeParameters(MultiPartReaderClientSide.java:227)
    at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readMultiPart(MultiPartReaderClientSide.java:154)
    at com.sun.jersey.multipart.impl.MultiPartReaderServerSide.readMultiPart(MultiPartReaderServerSide.java:80)
    at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:144)
    at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:82)
    at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:488)
    at com.sun.jersey.server.impl.model.method.dispatch.EntityParamDispatchProvider$EntityInjectable.getValue(EntityParamDispatchProvider.java:123)
    at com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:46)
    at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:153)
    at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:203)
    at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)

Here’s the relevant piece of code from Jersey

protected static MediaType unquoteMediaTypeParameters(final MediaType mediaType, final String... parameters) {
235        if (parameters == null || parameters.length == 0) {
236            return mediaType;
237        }
238
239        final HashMap unquotedParams = new HashMap(mediaType.getParameters());
240
241        for (final String parameterName : parameters) {
242            String parameterValue = mediaType.getParameters().get(parameterName);
243
244            if (parameterValue.startsWith("\"")) {
245                parameterValue = parameterValue.substring(1, parameterValue.length() - 1);
246                unquotedParams.put(parameterName, parameterValue);
247            }
248        }
249
250        return new MediaType(mediaType.getType(), mediaType.getSubtype(), unquotedParams);
251    }

The error occurs because Jersey Server expects the boundary parameter be set as a part of the content-type header, which is not being set by Apache HTTP Client. It can be verified by looking at the request made by Jersey client vs Apache client

Jersey Client

Content-Type=multipart/form-data;boundary=Boundary-1234567890

Apache HTTP Client

Content-Type=multipart/form-data

And since the boundary parameter is missing, it ends up throwing a NPE.

SOLUTION

I was able manually hack in the boundary parameter into the Content-Type header of the request making it available for Jersey parser and thus avoiding the NPE. The issue with this fix however is that the class MultipartFormEntity is package private and therefore, the utility class described below needs to be created in the package org.apache.http.entity.mime

package org.apache.http.entity.mime;

import org.apache.commons.lang3.Validate;
import org.apache.http.HttpEntity;

public class MultiPartEntityUtil {
	
	public static String getBoundaryValue(HttpEntity entity) {
		Validate.notNull(entity);
		
		if( entity instanceof MultipartFormEntity ) {
			MultipartFormEntity formEntity = (MultipartFormEntity)entity;

			AbstractMultipartForm form =  formEntity.getMultipart();
			Validate.notNull(form);
			
			return form.getBoundary();
		}
		
		throw new IllegalArgumentException("Provided entity is of type: " + entity.getClass() + " instead of expected: MultipartFormEntity");
	}

}

With this utility class, we can simply set the Content-Type header as follows

 MultipartEntityBuilder builder = MultipartEntityBuilder.create();
 builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

for (File file : files) {
    builder.addBinaryBody(file.getName(), file, ContentType.DEFAULT_BINARY, file.getName());
}

HttpEntity entity = builder.build();
String boundary= MultiPartEntityUtil.getBoundaryValue(entity);

...

request.addHeader(HttpHeaders.CONTENT_TYPE, "multipart/form-data;boundary="+boundary);

This hack makes sure that Jersey server finds the appropriate boundary parameter. Now you can successfully do multipart uploads with Apache client on Jersey 1.x