-
Notifications
You must be signed in to change notification settings - Fork 0
Home
You are familar with programming an ASAP peer?. Very good. Let's talk about components.
But before we start:: Add two additional libraries to your project: SharkPeer and ASAPHub.
This is out of the way now. Let's talk about our component model.
Your apps would most probably be helpful in other applications. We need components. We need a way to put them together. That is what we call Shark – Shared Knowledge. It is a concept: Implement decentralized apps (based on ASAP) and make them work together.
It is not even difficult. Each ASAP application uses an ASAPPeer to communicate with others. Applications can be distinguished by a format. Obviously:
- Different applications must not use the same format. ASAP itself uses some formats for internal management purposes. They must not be used either.
Applications might have dependencies. There is for instance an ASAP application that manages certificates. It is strongly recommended to use it instead implementing your own. This application must be initialized before an application that uses it.
- Applications must be initialized / created in a well-defined order. There must be a way to get a reference to applications we want to use in our own.
Those applications will share a single ASAPPeer. It must know all formats within that larger application before it is started. There is no way around:
- Setting up such an united applications is a two step process: First, all components have to be initialized and have to announce their formats. Second, the ASAPPeer can be started.
Your ASAP application has to become a SharkComponent to become a part of such a united ASAP Application – a Shark Application.
Here is an example:
@ASAPFormats(formats = {YourComponent.FORMAT_A, YourComponent.FORMAT_B})
public class YourComponent implements SharkComponent, YourFacade {
public static final String FORMAT_A = "myApp://formatA";
public static final String FORMAT_B = "myApp://formatB";
...
}
There must be a single interface (or class) that describes your ASAP application (YourComponent
). It must implement SharkComponent
but also offer all methods of your application (symbolized by YourFacade
). The list of your interfaces could be longer. In general, it is good idea to follow the Facade Pattern when sharing a software component, though.
The @ASAPFormats
annotation is mandatory. All supported formats must be declared with the formats
parameter. That's it. You have successfully declared your ASAP application as Shark Component. Other example(s): CertificateExchange
That is actually a bad example. We strongly suggest to use a single format for each application. Nevertheless, in rare cases, more than one is necessary. Just one format is better, though.
Who could better describe the creation of your application then you? You do not want to explain others how to do this? Even if you would: Would you like to read lengthy explanations of others? I do not think so.
Fortunately, there is design pattern for that: Factory pattern. You provide code that sets up your applications. That code is in a factory object.
public class YourComponentFactory implements SharkComponentFactory {
@Override
public SharkComponent getComponent() {
YourComponent yourComponentInstance = …;
// do your initialization / creation
return yourComponentInstance;
}
}
Finally, we need to explain how to set up a united application. The SharkPeer represents this unification. It represents the collection of more than one ASAP application. There is one implementation of this interface now: SharkPeerFS.
static final CharSequence ALICE = "Alice";
static final CharSequence ROOTFOLDER = "sharkComponent";
static final CharSequence ALICE_ROOTFOLDER = ROOTFOLDER + "/" + ALICE;
...
SharkPeerFS sharkPeer = new SharkPeerFS(ALICE, ALICE_ROOTFOLDER);
// add another application
AnotherComponentFactory factory = new AnotherComponentFactory();
sharkPeer.addComponent(factory, AnotherComponent.class);
// add your application
YourComponentFactory factory = new YourComponentFactory();
sharkPeer.addComponent(factory, YourComponent.class);
// add an additional one with dependencies
AnotherComponent requiredComponent = sharkPeer.getComponent(AnotherComponent.class);
DependendComponentFactory factory = new DependendComponentFactory(requiredComponent);
sharkPeer.addComponent(factory, YourComponent.class);
// launch Shark peer
sharkPeer.start();
SharkPeerFS works with ASAPPeerFS. It requires a peer name and folder name to keep data. Components can be added. Users of your application should only need to read and understand your YourFacade
and must be able to create a factory object of yours (YourComponentFactory
).
- Note: Your application cannot choose peer name and rootfolder by itself any longer. Those parameters are defined with SharkPeer creation. If you need them: There are two ways to get them.
Here is the first way – not the preferred one, though: Define you factory constructor in that way, like
public class YourComponentFactory implements SharkComponentFactory {
YourComponentFactory(CharSequence peerName, CharSequence folder) {
// keep it
}
...
}
-
Note: Components which are required from others could and should be parameter of the factory as illustrated with
DependendComponentFactory
. -
Note: Components can only be added and removed until the Shark peer is started
The startup process is very simple: An ASAPPeer is created with the collection of all supported formats. Each component is informed about this action: The void onStart(ASAPPeer peer)
is called. Your component, your ASAP application has got access to the ASAPPeer object and can act as usual. This is the second and preferred way to get access to peer parameters like its name.
The following code is from the ASAP Certificate project
@ASAPFormats(formats = {ASAPCertificateStore.CREDENTIAL_APP_NAME, ASAPCertificateStorage.CERTIFICATE_APP_NAME})
public class SharkCertificateComponent implements SharkComponent, ASAPKeyStore, ASAPCertificateStore {
private FullAsapPKIStorage asapPKIStorage = null;
@Override
public void onStart(ASAPPeer asapPeer) throws SharkException {
try {
ASAPStorage asapStorage = asapPeer.getASAPStorage(asapPeer.getPeerName());
ASAPCertificateStorage asapAliceCertificateStorage =
new ASAPAbstractCertificateStore(asapStorage, asapPeer.getPeerName(), asapPeer.getPeerName());
InMemoASAPKeyStore inMemoASAPKeyStore = new InMemoASAPKeyStore(asapPeer.getPeerName());
this.asapPKIStorage = new FullAsapPKIStorage(asapAliceCertificateStorage, inMemoASAPKeyStore);
} catch (IOException | ASAPException e) {
throw new SharkException(e);
}
}
…
private void checkStatus() throws SharkStatusException {
if(this.asapPKIStorage == null) {
throw new SharkStatusException("ASAP peer not started component not yet initialized");
}
}
// just an example of a interface implementation
@Override
public PublicKey getPublicKey(CharSequence charSequence) throws ASAPSecurityException {
this.checkStatus(); // it would produce an exception if called before the Shark Peer was started
return this.asapPKIStorage.getPublicKey(charSequence); // delegate call
}
...
}
Details of the algorithm in the onStart
method are not relevant but one fact is:
The actual creation of this component is made in the onStart
method and not in the factory method. Calling any method before the SharkPeer was started would produce a SharkStatusException
, see line this.checkStatus();
in getPublicKey
. This pattern separates the creation of the component object from setting up its functions. This class also follows the Delegation pattern.
Here is the factory implementation:
public class SharkCertificateComponentFactory implements SharkComponentFactory {
private SharkCertificateComponent instance = null;
@Override
public SharkComponent getComponent() {
if(this.instance == null) {
this.instance = new SharkCertificateComponent();
}
return this.instance;
}
}
An object is created but nothing is initialized. Initialization requires an ASAPPeer and is made in void onStart(ASAPPeer)
instead.
This library add some functions to ASAPPeer. Most importantly:
- What's a hub
- hub information management
- connection management