2012/08/17

fine grained control

September and the return of the normal flow of things are just around the corner. For this holiday post I'm going to share another snippet of code that I've recently been working on. It gives you fine grained control over NetKernel's kernel properties :

// Author: Tom Geudens
// Date  : 2012/08/15

// The usual suspects for an accessor.
import org.netkernel.layer0.nkf.*;
import org.netkernel.layer0.meta.impl.SourcedArgumentMetaImpl;
import org.netkernel.module.standard.endpoint.StandardAccessorImpl;

// Processing.
import java.util.Properties;
import org.netkernel.container.IKernel;
import org.netkernel.layer0.boot.*;
import java.io.ByteArrayOutputStream;

import org.netkernel.layer0.representation.IBinaryStreamRepresentation;

// The accessor itself.
public class KernelPropertyAccessor extends StandardAccessorImpl {

    public KernelPropertyAccessor() {
        this.declareThreadSafe();
        this.declareArgument(new SourcedArgumentMetaImpl("key",null,null,new Class[] {String.class}));
        this.declareArgument(new SourcedArgumentMetaImpl("value",null,null,new Class[] {String.class}));
        this.declareSourceRepresentation(String.class);
        this.declareInhibitCheckForBadExpirationOnMutableResource(); // golden thread takes care of it
        this.declareSupportedVerbs(
                INKFRequestReadOnly.VERB_NEW|
                INKFRequestReadOnly.VERB_DELETE|
                INKFRequestReadOnly.VERB_EXISTS|
                INKFRequestReadOnly.VERB_SOURCE|
                INKFRequestReadOnly.VERB_SINK);
    }
   
    public void onSource(INKFRequestContext aContext) throws Exception {
        // SOURCE requires one argument, key, which is mandatory for all
        // verbs and checked by the grammar.
        String aKey = aContext.getThisRequest().getArgumentValue("key");
        
        // Check validity of arguments.
        if ( aKey.equals("") ) {
            throw new NKFException("request does not contain a valid key argument");
        }

        // getting the properties data
        Properties vKernelProperties = new Properties();
        IKernel aKernel = aContext.getKernelContext().getKernel();
        vKernelProperties.load(BootPersistence.sourceBootResource("kernel.properties",aKernel).getInputStream());

        if (! vKernelProperties.containsKey(aKey)) {
            throw new NKFException("property - " + aKey + " - does not exist in kernel.properties");
        }
        
        INKFRequest vGTrequest = aContext.createRequest("active:attachGoldenThread");
        vGTrequest.addArgument("id", "gt:kp:" + aKey);
        aContext.issueRequest(vGTrequest);

        // response (string)
        aContext.createResponseFrom(vKernelProperties.getProperty(aKey));
    }

    public void onExists(INKFRequestContext aContext) throws Exception {
        // EXISTS requires one argument, key, which is mandatory for all
        // verbs and checked by the grammar.
        String aKey = aContext.getThisRequest().getArgumentValue("key");

        // Check validity of arguments.
        if ( aKey.equals("") ) {
            throw new NKFException("request does not contain a valid key argument");
        }
        
        // getting the properties data
        Properties vKernelProperties = new Properties();
        IKernel aKernel = aContext.getKernelContext().getKernel();
        vKernelProperties.load(BootPersistence.sourceBootResource("kernel.properties",aKernel).getInputStream());

        INKFRequest vGTrequest = aContext.createRequest("active:attachGoldenThread");
        vGTrequest.addArgument("id", "gt:kp:" + aKey);
        aContext.issueRequest(vGTrequest);

        // response (boolean)
        aContext.createResponseFrom(vKernelProperties.containsKey(aKey));
    }
   
    public void onNew(INKFRequestContext aContext) throws Exception {
        // NEW requires two arguments, key, which is mandatory for all
        // verbs and value, which is only mandatory for NEW and SINK.
        String aKey = aContext.getThisRequest().getArgumentValue("key");
        String aValue = null;
        if (aContext.getThisRequest().argumentExists("value")) {
            aValue = aContext.getThisRequest().getArgumentValue("value");
        }

        // Check validity of arguments.
        if ( aKey.equals("") ) {
            throw new NKFException("request does not contain a valid - key - argument");
        }
        if ( aValue == null) {
            throw new NKFException("request does not contain a valid - value - argument");
        }

        // getting the properties data
        Properties vKernelProperties = new Properties();
        IKernel aKernel = aContext.getKernelContext().getKernel();
        vKernelProperties.load(BootPersistence.sourceBootResource("kernel.properties",aKernel).getInputStream());

        if (vKernelProperties.containsKey(aKey)) {
            throw new NKFException("property - " + aKey + " - already exists in kernel.properties");
        }
        
        // adding new key/value
        ByteArrayOutputStream vBAOS = new ByteArrayOutputStream();
        vKernelProperties.setProperty(aKey,aValue);
        vKernelProperties.store(vBAOS, null);
        
        IBinaryStreamRepresentation vBSR =
                aContext.transrept(vBAOS.toString().toString(), IBinaryStreamRepresentation.class);
        
        BootPersistence.sinkBootResource("kernel.properties",vBSR,aKernel);
        
        // response, the newly created property
        aContext.createResponseFrom(aKey + "=" + aValue);
    }

    public void onSink(INKFRequestContext aContext) throws Exception {
        // SINK requires two arguments, key, which is mandatory for all
        // verbs and value, which is only mandatory for NEW and SINK.
        String aKey = aContext.getThisRequest().getArgumentValue("key");
        String aValue = null;
        if (aContext.getThisRequest().argumentExists("value")) {
            aValue = aContext.getThisRequest().getArgumentValue("value");
        }

        // Check validity of arguments.
        if ( aKey.equals("") ) {
            throw new NKFException("request does not contain a valid - key - argument");
        }
        if ( aValue == null) {
            throw new NKFException("request does not contain a valid - value - argument");
        }

        // getting the properties data
        Properties vKernelProperties = new Properties();
        IKernel aKernel = aContext.getKernelContext().getKernel();
        vKernelProperties.load(BootPersistence.sourceBootResource("kernel.properties",aKernel).getInputStream());

        if (! vKernelProperties.containsKey(aKey)) {
            throw new NKFException("property - " + aKey + " - does not exist in kernel.properties");
        }
        
        // replacing the value of a key
        ByteArrayOutputStream vBAOS = new ByteArrayOutputStream();
        vKernelProperties.setProperty(aKey,aValue);
        vKernelProperties.store(vBAOS, null);
        
        IBinaryStreamRepresentation vBSR =
                aContext.transrept(vBAOS.toString().toString(), IBinaryStreamRepresentation.class);
        
        BootPersistence.sinkBootResource("kernel.properties",vBSR,aKernel);

        // SINK has no response but we do need to cut the golden thread
        INKFRequest vGTrequest = aContext.createRequest("active:cutGoldenThread");
        vGTrequest.addArgument("id", "gt:kp:" + aKey);
        aContext.issueRequest(vGTrequest);
    }

    public void onDelete(INKFRequestContext aContext) throws Exception {
        // DELETE requires one argument, key, which is mandatory for all
        // verbs and checked by the grammar.
        String aKey = aContext.getThisRequest().getArgumentValue("key");

        // Check validity of arguments.
        if ( aKey.equals("") ) {
            throw new NKFException("request does not contain a valid - key - argument");
        }

        // getting the properties data
        Properties vKernelProperties = new Properties();
        IKernel aKernel = aContext.getKernelContext().getKernel();
        vKernelProperties.load(BootPersistence.sourceBootResource("kernel.properties",aKernel).getInputStream());

        if (! vKernelProperties.containsKey(aKey)) {
            throw new NKFException("property - " + aKey + " - does not exist in kernel.properties");
        }
        
        // removing the key
        ByteArrayOutputStream vBAOS = new ByteArrayOutputStream();
        vKernelProperties.remove(aKey);
        vKernelProperties.store(vBAOS, null);
        
        IBinaryStreamRepresentation vBSR =
                aContext.transrept(vBAOS.toString(), IBinaryStreamRepresentation.class);
        
        BootPersistence.sinkBootResource("kernel.properties",vBSR,aKernel);

        INKFRequest vGTrequest = aContext.createRequest("active:cutGoldenThread");
        vGTrequest.addArgument("id", "gt:kp:" + aKey);
        aContext.issueRequest(vGTrequest);

        // response (boolean)
        INKFRequest vKPrequest = aContext.createRequest("active:kernelproperty");
        vKPrequest.addArgument("key", aKey);
        vKPrequest.setVerb(INKFRequestReadOnly.VERB_EXISTS);
        aContext.createResponseFrom(!(Boolean)(aContext.issueRequest(vKPrequest)));
    }
}
 

My code doesn't often come with warnings, but this time I have to state it is delivered "as is" and that changing kernel properties can potentially mess up your system (for which I take no responsibility).

I can also see some possible improvements on the above code, so by all means try it out and change it as you like.

Enjoy !