Skip to content
This repository has been archived by the owner on Jan 9, 2023. It is now read-only.

Programmatic Access

Marco Brandizi edited this page Jan 18, 2016 · 34 revisions

As mentioned above, the myequivalents-core contains the definition of general interfaces to access the myEquivalents functionality. The core module contains only such abstract interfaces and a configuration mechanism (based on Spring) to create and obtain specific instances of such interfaces. You must select a specific implementation, such as the one available from the myequivalents-db module, in order to make things working.

The entry point to myEquivalents is the manager factory. This uses the factory pattern to get managers to pieces or functionality. While you can explicitly instantiate a specific implementation of the manager factory (e.g., new DbManagerFactory(...)), we recommend to use the Resource class, which is based on Spring Framework and allows you to define the specific manager factory that you need in a Spring metadata configuration file. This is a powerful and flexible mechanism, as it is shown in the configuration section.

##Linking myEquivalents to your application, via Maven If your application is built through Maven, as we recommend, the details are as follow.

  • Use the EBI repository in your Maven's POM:
<repository>
  <id>EBIBioSamples-GH-repo</id>
  <url>https://raw.githubusercontent.com/EBIBioSamples/EBIBioSamples.github.io/maven-repo</url>
  <snapshots>
    <enabled>true</enabled>
  </snapshots>
</repository>
  • Declare the core dependency, or, more realistically, a dependency on a specific implementation:
<dependency>
  <groupId>uk.ac.ebi.fg</groupId>
  <artifactId>myequivalents-db</artifactId>
  <version>0.2-SNAPSHOT</version><!-- or the last version! -->
</dependency>
  • To use the Spring-based configuration mechanism, make a file like myeq-manager-config.xml available to the Java classpath. In Maven, this file is usually located into src/main/resources or src/test/resources. An example copy of such file can be taken from the binary build for the myequivalents-cmdline distribution. Parameterised versions of such file (which are populated with real value by Maven profiles) are in the db module.

This is a Spring metadata file that defines the bean named myEquivalentsManagerFactory, an instance of the ManagerFactory interface. The default version of such file instantiates the DbManagerFactory class, the implementation based on a relational database. You can define Hibernate and connection parameters for such factory class straight in such metadata file.

##Linking as a .jar While do not officially support builds outside Maven, if that is your case, the following should work.

  • Download the core .jar, from here.
  • Download the .jar corresponding to the back-end that you need, for example the relational back-end, or build it from the myequivalents sources, going to root and issuing 'mvn package' (the final jar will be somewhere like myequivalents-db/target/, see building instructions for details).
    • Note that these jar files contain only the myEquivalents core functionality and not 3rd party dependencies, which you can list from the POM at the same URL. If you want a .jar containing all that is needed, build the command-line module and get myequivalents_deps.jar from the target/ directory.
  • Define a proper myeq-manager-config.xml metadata file for your project, as explained above, and put it in the classpath (or link it to your project the way recommended by your IDE).

##Obtaining Managers The following examples are mostly taken from our JUnit tests. You should access the myEquivalents system starting from getting the pre-configured manager factory:

ManagerFactory mgrFactory = Resources.getInstance ().getMyEqManagerFactory ();

This will lead you to the bean named myEquivalentsManagerFactory and defined in the myeq-manager-config.xml file. Once you have a factory, you can get the manager you need, for instance:

ServiceManager serviceMgr = mgrFactory.newServiceManager();
// Of course you can do it quicker: 
// ServiceManager serviceMgr = Resources.getInstance ().getMyEqManagerFactory ().newServiceManager();

In the following sections we show how to manage the mapping entities available in the myEquivalents model. Please refer to this presentation for an overview of such model.

##Service-related interfaces Defining a new service

service1 = new Service ( "test.testservmgr.service1", "testservmgr.someType1", "A Test Service 1", "The Description of a Test Service 1" );
service1.setUriPattern ( 
  "http://somewhere.in.the.net/testservmgr/service1/someType1/${accession}" );

sc1 = new ServiceCollection ( 
  "test.testservmgr.serviceColl1", service1.getEntityType (), "Test Service Collection 1", 
  "The Description of the SC 1" 
);
service1.setServiceCollection ( sc1 );

repo1 = new Repository ( "test.testservmgr.repo1", "Test Repo 1", "The Description of Repo1" );
service1.setRepository ( repo1 );

service2 = new Service (...);

// This requires that you get a service manager via regular authentication, see below
serviceMgr.storeServices ( service1, service2 );

Service-related information can also be uploaded by using XML, pretty much the same way you do with the command line (see below):

String xml =
"<service-items>\n" +
"  <services>\n" +
"    <service uri-pattern='http://somewhere.in.the.net/testservmgr/service6/someType1/${accession}'\n" + 
"           entity-type='testservmgr.someType1' title='A Test Service 6' name='test.testservmgr.service6'>\n" +
"      <description>The Description of a Test Service 6</description>\n" + 
"    </service>\n" + 
"    <service entity-type='testservmgr.someType7' title='A Test Service 7' name='test.testservmgr.service7'" +
"           repository-name = 'test.testservmgr.repo1'" +
"           service-collection-name = 'test.testservmgr.serviceColl1'>\n" +
"      <description>The Description of a Test Service 7</description>\n" +
"    </service>\n" +
"    <service entity-type='testservmgr.someType2' title='A Test Service 8' name='test.testservmgr.service8'>\n" + 
"      <description>The Description of a Test Service 8</description>\n" + 
"    </service>\n" +
"  </services>\n" +
"</service-items>";

// This requires proper authentication see below
serviceMgr.storeServicesFromXML ( new StringReader ( xml ) );

Fetching services by name

// If you aren't authenticated, or you only have the viewer role, here you get back public services only, see
// below for details.
ServiceSearchResult result = serviceMgr.getServices ( 
  "test.testservmgr.service6", "test.testservmgr.service7", "test.testservmgr.service8" );
for ( Service service: result.getServices () )
  // service object accessible here

ServiceManager can also be used to lookup service-collections ( getServiceCollections() ) and repositories( getRepositories() ) by name.

ServiceManager also contains methods to delete services ( deleteServices() ) and related objects.

##Mapping-related interfaces Storing mappings

EntityMappingManager emMgr = Resources.getInstance ().getMyEqManagerFactory ().newEntityMappingManager();

// bundle b1 ( (s1, b1.1) (s2, b1.2) (s1, b1.3)
// bundle b2 ( (s2, b2.1) (s3, b2.2) )

// Stores a whole equivalence class (a bundle). You need to be an authenticated editor or administrator
emMgr.storeMappingBundle ( 
  service1.getName () + ":b1.1", service2.getName () + ":b1.2", service1.getName () + ":b1.3" );

// Store a pair of entities that are linked together (i.e., are equivalent)
emMgr.storeMappings ( 
  service2.getName () + ":b2.1", service3.getName () + ":b2.2"
);

Fetching mappings

// Fetches all the bundles each of the parameter entities belongs to
// If you aren't authenticated, or you don't have the editor role, you will get public mappings only (see below) 
EntityMappingSearchResult result = emMgr.getMappings ( 
  false, service1.getName () + ":b1.3", service3.getName () + ":b2.2" 
);

for ( Bundle bset: result.getBundles () )
  for ( Entity entity: bset.getEntities () )
    // entity.getService() and entity.getAccession()

##Storing/Fetching mappings via URI identifiers

As explained in Architecture, URIs can be used to refer to mapped entities:

eMgr.storeMappings ( 
  ":<http://somewhere.in.the.net/testservmgr/service6/someType1/acc1", "test.testservmgr.service6:acc2" 
);

// Automatic conversion int the other form
//
EntityMappingSearchResult result = emMgr.getMappings ( "test.testservmgr.service6:acc1" );

// gives the same result
result = emMgr.getMappings ( "_:<http://somewhere.in.the.net/testservmgr/service6/someType1/acc1>" );

// still equivalent, but a bit slower at first (must search the service that matches)
result = emMgr.getMappings ( "<http://somewhere.in.the.net/testservmgr/service6/someType1/acc1>" );

##User and permission administration

When nothing else is specified, the managers that you obtain from the manager factory grant read-only access to myEquivalents public data. In order to be able to access reserved data and perform changes, you need to own a myEquivalents user account having proper permissions.

##Obtaining Managers, with authentication This is an example:

In order to log in with another user, you have to use the following code.

ServiceManager serviceMgr = mgrFactory.newServiceManager ( "test.user@somewhere.net", "test.secret" );

When you acquire a manager without specifying any user details, myEquivalents implicitly link your manager instance to a special, anonymous user, who has minimal rights.

###Types of authentication The call in this example makes a 'API-related authentication', i.e., an kind of myEquivalents login that can be used to access myEquivalents mappings and related operations. A 'password secret' is associated to a myEquivalents user that can be used for this type of authentication.

There is another type of myEquivalents login, available for the AccessControlManager, the full user authentication:

AccessControlManager accMgr = mgrFactory.newAccessControlManagerFullAuth ( "test.user@somewhere.net", "test.password" );

when you login in full mode, you have additional access to your account, for example to change your name or your passwords. The idea of having two login types is that the full authentication is more critical and should not be used for most common operations, which are typically present in your client code. In future, we plan to develop a web interface to access user-administration and similar actions. In such a scenario, the full authentication will typically used by human beings via such interface, while the regular authentication will be reserved to user's applications.

###User roles and access levels

  • The access model in myEquivalents is very simple:
  • Entities (mapped entities, services, repositories and service collections) can be either private or public. Whether an entity is public or not is determined by a combination of an explicit 'public' flag and a release date attribute, with the former having priority.
  • User accounts are associated to a role of viewer, editor or administrator. Viewers can only read public entities. Editors can read both private and public entities and additionally make changes related to mapping. Administrators can do everything, including adding new users and changing any user's information or role. All users, including non administrators, but excluding the special anonymous user, can change information about their own account, such as their name and passwords, but only administrators can create new users change another user or change any user's role.

As you can see, this access model is very basic. The idea is that a myEquivalents installation is managed by a small group of collaborating people, they might need to distinguish between published/non published data, but likely they won't need to split users and data in isolated groups. An organisation having such separated groups should deploy different myEquivalents instances (e.g., different relational databases, and possibly multiple web applications for the web service, each configured with its own URL and Spring bean file).

WARNING: if your configuration is accessing a relational back end, users will be able to read the database password from the Spring configuration file and bypass myEquivalents permission control altogether, either by using SQL, or by accessing myEquivalents objects by means of low-level interfaces like DAOs. There isn't anything we can do in such a case, you should set up the web service if you want to enforce the myEquivalents access model. When you use the relational database, but you access it via myEquivalents managers, as we recommend to do, such model is still enforced, since this makes things simpler and cleaner.

Related to this, [HTTP/SSL connections are recommended](TODO: how to enforce them in Tomcat), so that you can ensure an acceptable degree of protection.

###Accessing users and permissions through the access control manager permissions and users are available through the AccessControlManager. The following are examples of usage, mostly taken from JUnit Tests:

Accessing user data

// As usually, ask to the factory and with proper credentials
AccessControlManager accMgr = mgrFactory.newAccessControlManagerFullAuth ( "admin@foo.net", "test.password" );
// You can create new users if you're an admin and fully authenticated
User user = new User ( "test.user@foo.net", "Test", "User", "user.pass", "test notes", Role.VIEWER, "user.secret" );
accMgr.storeUser ( user );

// You can get your account details and make changes:
AccessControlManager accMgr = mgrFactory.newAccessControlManagerFullAuth ( "test.user@foo.net", "test.password" );
User user = accMgr.getUser ( "test.user@foo.net" );
user.setNotes ( "Modified User Notes" );
accMgr.store ( user );

// But this will generate an exception, unless you're a fully authenticated admin.
// Similarly you cannot access other users if you aren't an admin
user.setRole ( Role.ADMIN );
accMgr.store ( user );

Storing user credentials in your application code

As you can see in the examples above, it's unavoidable that you store application credentials on the code that invokes myEquivalents operations. That is the reason why we make the distinction between API secret and user password. The former will typically be in the code or in a configuration file, while the user password will used more rarely, for user-related changes.

Changing entities visibility

// Entities are saved with the visibility you set up via their accessors
Service service = new Service ( "test.perms.service1", "someType", "A Test Service", "The Description of a Test Service" );
// DateMidnight is http://www.joda.org/joda-time/, which use is recommended
service.setReleaseDate ( new DateMidnight ( 2013, 4, 25 ).toDate () ) 
ServiceManager servMgr = mgrFactory.newServiceManager ( "test.editor", "test.secret" );
servMgr.storeServices ( service );

Now the service is private until April/25/2013, since no publicFlag is specified. AccessControlManager's methods should be more practical for existing entities:

// This methods in the access control manager should be easier for existing entities
accMgr.setServicesVisibility ( "true", new DateMidnight ( 2020, 1, 1 ).toDate () , true, service.getName () );
// Now the service is explicitly public (first parameter), independently on the release date (second parameter has put it in the future).

Note that the service's manager visibility is cascaded to child entities (third parameter set to true), any entity participating in a mapping that has no visibility specified (no public-flag, no release date) inherits visibility from the service it belongs to. Inheritance applies to the Repository->Services->Mapped entities chain. The Service Collection->Services chain applies too, but only when AccessControlManager.setServiceCollectionsVisibility() is used, i.e. inheritance is not inferred during reads. That is for the sake of simplicity and to avoid confusion between the two chains.