WikiPDB:Api
From WikiPDB
WikiPDB has an open API for writing error check plug-ins. An error check plug-in is a simple application (preferably written in php) that is capable of communicating with the WikiPDB through the API described bellow, and discovers errors (or suspicious records that might be errors, but may as well be correct) in PDB files. To make writing plug-ins simple we provide a php class, and a sample code below, that might be used without any restrictions!
Completed WikiPDB plug-ins will be considered for inclusion into the list of standard plug-ins by the PITGroup. Developers of WikiPDB plug-ins are strongly encouraged to start the registration process as soon as they have the final concept, so that we can avoid parallel development of similar plug-ins, or rejection of plug-ins that have already been implemented.
To start the registration please send a very short summary on the type of errors that will supposedly be detected by the plug-in and a summary of the method used to "register (at) wikipdb (dot) org". If requested we will treat the description of the method confidentially, and it will only be used to decide if the plug-in is worth for inclusion in our system.
Note, that registered plug-ins are either hosted by the developer or PITGroup. Plug-ins hosted by the PITGroup have to go through a more strict registration process, and all source files will be requested, so that it can be decided if the software components provided by the developer will not cause any damage to PITGroup servers. On the other hand plug-ins hosted by the developer can be registered without providing any part of the source or any executable, only the short descriptions mentioned in the previous paragraph are required. Hosting by the developer is encouraged, as the registration process is simpler, and does not require the developer to reveal any confidential information to the PITGroup.
Contents |
Quick Start
The easiest way of creating a new plug-in for WikiPDB is to use the abstract error check client class, that is pre written for you in php. In what follows we expect a basic knowledge of php. To find out more about php and seting up your php server please follow the links.
Setting up the necessary environment
Once the php server is up and running create a separate directory for your wikipdb plugins, and it is a good idea, to create another separate directory for each of the plug-ins. Copy the wikipdb:AbstractErrorCheckClient and wikipdb:HttpClient scirpts, and save them into a separate includes directory.
Hello world plug-in
The simplest WikiPDB plug-in would be one that finds no errors at all, but returns a help file, and the details of the found errors. (The later would obviously be an empty list of details.) Below is an implementation of exactly this plug-in, with comments for you to make it easy to understand which chunk of code is responsible for certain things.
<? /* ** For this to work we will need the AbstractErrorCheckClient and the httpClient ** and they should already be in an include directory. The exact location of these ** files is totally up to the user, but the include path below may need to be ** corrected. */ require_once("./inc/AbstractErrorCheckClient.php"); require_once ("./inc/httpClient.php" ); /* ** Lets create an error check class, as an extension of our AbstractErrorCheckClient */ class TrivialErrorCheckClient extends AbstractErrorCheckClient { /* ** This is the most important function, that will do the search for errors, ** and save them somehow, preferably in an SQL database. (Though saving in ** files is just as fine.) The return value should be an associative array ** that has a numeric value for the 'errors' and 'warning' keys. */ protected function userDefinedErrorcheck() { $retVal['errors']=0; $retVal['warning']=0; return $retVal; } /* ** This function should print an HTML help file for WikiPDB users. ** Apart from including useful information about what kind of errors are ** being searched for, the documentation of useractions and information ** about the plug-ins creator should also be included here. */ protected function help() { echo "<html><head><title>Hello World help</title></head><body>". "<h1>Hello World!</h1><p>This is a useless plug-in, created ". "by the PIT Group for educational purposes!</p></body></html>"; } /* ** This function should print details about the errors the plug-in found ** in a human readable form. Please try to be as descriptive as possible ** and use highlighting when ever see fit. A list of possible corrections ** is also welcome, when it is possible to generate such. */ protected function details() { echo "<html><head><title>Hello World details</title></head><body>". "<h1>Hello World!</h1><p>We found no errors!</p></body></html>"; } /* ** This function should print details about the errors the plug-in found ** in a machine readable form, preferably as a JSON encoded class or array. ** This is optional, though highly encouraged, as with a little extra work ** valuable information is made easily available for other plug-ins. */ protected function apiDetails() { echo json_encode(array()); } /* ** Useractions should be implemented in this function. */ protected function useraction() { } } /* ** Once the plug-in class is ready, all we need to do is create an instance of it. ** The first argument of the constructor is the name of the plug-in, that will ** appear on the WikiPDB user interface. ** The second argument of the constructor is optional. Provide a space separated ** list of plug-in ids corresponding to other wikipdb plug-ins that should finish ** running before this plug-in is started. For example it is a good idea to add ** plug-in id of the syntax checker plug-in (it is plugin number 1) to this list ** if you expect the PDB file to be syntactically correct. */ try { new TrivialErrorCheckClient("Trivial errorcheck client",""); } catch(Exception $e) { echo "Exception > ".$e->getMessage(); exit(); } ?>
When ever a new plug-in is to be written, it is a good idea to start by copying the above code into an index.php, and edit it as necessary.
Testing and debugging your plug-in
During the development of a plug-in one may need to do test runs. Basically there are two ways of doing this in case of WikiPDB.
The first solution is intended for plug-ins that do not use results of other plug-ins, so they can run independently without waiting for other plug-ins to finish. I this case the simplest way to do a test run, is to use the built-in debug action of the AbstractErrorCheckClient class. In this case the plug-in will expect a pdbid, and a revision id as get variables, and the action get variable should be set to debug. Here is an example: http://plugins.wikipdb.org/syntax/?action=debug&pdbid=10gs&revisionid=1 After the debug run the details page is available by setting the action variable to details: http://plugins.wikipdb.org/syntax/?action=details&pdbid=10gs&revisionid=1
The other way of doing test runs might be more convenient in certain cases, but can be slow, as in this case the wikipdb system dose a complete error check with all of the registered plug-ins, and the extra user plug-ins specified by the user. To set your list of user plug-ins go to the DataWiki Preferences page, and provide a space separated list of links to your plug-ins. After saving your plug-ins will be included into every subsequent error checks. User plug-ins get subsequent plug-in ids starting with 1001.
Note, that a WikiPDB plug-in communicates with the WikiPDB server, hence it is not possible to write error messages into the output of your plug-in. The easiest work around for this problem is to write your debug messages into a file on your web server.
First "useful" plug-in
To showcase some of the powerful tools included in the AbstractErrorCheckClient, below we present a plug-in that will check if the first row of the PDB file is a HEADER record. To store the result of the error check, we will use an SQL table. To create the necessary table in mysql please execute the sql command below:
CREATE TABLE `header` ( `pdbid` char(4) NOT NULL, `revisionid` int(11) NOT NULL, `errors` text NOT NULL, PRIMARY KEY (`pdbid`,`revisionid`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1
And here is the source code for the HeadCheck plug-in. (Please update SQL access info as necessary.)
<? /* SQL access info */ define( "HOST", "localhost" ); define( "USERNAME", "" ); define( "PASSWD", "" ); define( "DATABASE", "" ); require_once("./inc/AbstractErrorCheckClient.php"); require_once ("./inc/httpClient.php" ); $conn=mysql_connect(HOST,USERNAME,PASSWD); if (!$conn) { echo mysql_error(); exit("MySQL connection failed"); } mysql_select_db(DATABASE); class HeaderCheckClient extends AbstractErrorCheckClient { protected function userDefinedErrorcheck() { /* Define an array that will temporarily store the list of errors */ $errors=array(); /* Use AbstractErrorCheckClients built in method to get a copy of the PDB revision we need to check. */ $pdbfile=$this->getPdbFileArray(); /* Do the checking */ if(substr($pdbfile[0],0,6)!='HEADER'){ $retVal['errors']=1; /* ** Here we add an element to the errors array, that is an associative array providing useful information about the error. ** This format is not obligatory, the way of storing is totally up to the developer, though this might serve as a suitable ** starting point when coming up with your own method of storing the errors. */ $errors[]=array('lineNo'=>1,'charNo'=>1,'charNoEnd'=>6, 'description'=>'First record should be a HEADER record, and not '.substr($pdbfile[0],0,5).'!', 'line'=>$pdbfile[0]); }else{ $retVal['errors']=0; } /* ** Save the result. If you decide to use files instead of an SQL database lookout for security leaks! ** NOTE that we use addslashes() so that quotation marks don't mess up the SQL query. */ mysql_query("INSERT INTO header (`pdbid`,`revisionid`,`errors`) VALUES ('{$this->pdbId}','{$this->revisionId}','". addslashes(json_encode($errors))."') ON DUPLICATE KEY UPDATE `errors`='".addslashes(json_encode($errors))."'"); $retVal['warning']=0; return $retVal; } protected function help() { echo "<html><head><title>Headcheck plugin help</title></head><body>\n\n"; echo "<p>This plug-in checks if the first 6 charecters in the PDB file is the key word ". "'HEADER'. Intended for educational purposes only!</p>"; echo "</body></html>"; } /* This function is added to the class, so that both details and apiDetails can use the same chunk of code to retrieve data from the SQL database. */ protected function getDetails() { if($result=mysql_query("SELECT * FROM header WHERE `pdbid`='{$this->pdbId}' and `revisionid`='{$this->revisionId}'")) { if($row=mysql_fetch_array($result)) { return $row['errors']; } else { die("Mysql error"); } } else { die("Mysql error"); } } protected function details() { $errors= json_decode($this->getDetails(),true); /* And this code chunk is copied from the syntax checking plug-in, and generates a human readable info sheet about the errors. */ ob_start("callback"); echo "<html><head><title>Headcheck plugin details</title></head><body>\n\n"; echo "<p>".count($errors)." errors!</p>"; $nums="12345678901234567890123456789012345678901234567890123456789012345678901234567890\n"; for($i=0;$i<min(count($errors),1000);$i++){ echo $errors[$i]['description']; echo "<br/>LineNo: ".$errors[$i]['lineNo']."; CharNo: ".$errors[$i]['charNo']."; "; echo "charNoEnd: ".$errors[$i]['charNoEnd'].";"; echo "<pre> 1 2 3 4 5 6 7 8\n"; echo substr($nums,0,$errors[$i]['charNo']-1); echo "<font color='red'>"; echo substr($nums,$errors[$i]['charNo']-1,$errors[$i]['charNoEnd']-$errors[$i]['charNo']+1); echo "</font>"; echo substr($nums,$errors[$i]['charNoEnd']); echo $errors[$i]['line']; echo "</pre><hr/>\n"; } echo "</body></html>"; ob_end_flush(); } protected function apiDetails() { echo $this->getDetails(); } protected function useraction() { } } try { new HeaderCheckClient("Headcheck plugin"); } catch(Exception $e) { echo "Exception > ".$e->getMessage(); exit(); } ?>
User actions
Sometimes - while doing an error check - one may calculate supplementary data, that is valuable on it's own. It would be nice if plug-ins could use these calculations performed by other plug-ins. User actions are intended to provide an interface for communication between plug-ins. Another way to utilize user actions, is to provide additional information pages for WikiPDB users apart from the details page.
A user action is invoked when the action get variable is set to useraction and the useraction get variable is set to any value other then null. The value of useraction get variable is available from the error check class (if defined as an extension of AbstractErrorCheckClient class) as $this->useractiontype.
Class reference
Class variables
Variables intended for direct access
- protected $revisionId
- The revision id of the file that is being checked for errors as specified by $_GET['revisionid'].
- protected $pdbId
- The pdb id corresponding to the file that is being checked for errors as specified by $_GET['pdbid'].
- protected $useractiontype
- A copy of $_GET['useraction'] that should only be used within the useraction() function to determine which useraction should be executed when there are more then one useractions defined
- protected $conditions
- The conditions of the plug-in as specified when the class constructor was invoked
- protected $conditionStatus
- Stores the status of other plug-ins at the time when the server sent a kick signal to the plug-in.
Variables that should not be used outside pre-writen class functions
- protected $action
- A copy of $_GET['action'] which is mainly used by the abstract class.
- protected $pluginName
- The name of the plug-in as specified when the class was initiated.
- protected $pdbFile
- Stores the PDB file after the first invocation of getPdbFile() or getPdbFileArray() actions. Use these functions to access data in this array.
- protected $returnUrl
- When the error check is ready results are sent back to this address.
- protected $callApiDetailsCash and protected $callUserActionCash
- Cash that stores data already retreaved either by callApiDetails or callUserAction functions.
Class methods
- public function __construct( $pluginName, $conditions = "" )
- Constructor
- $pluginName - An arbitary name for the plug-in. This is only used to identify the plug-in for WikiPDB end users.
- $conditions - Space separated list of plug-in IDs. The plug-in wont be invoked by WikiPDB until the plug-ins referenced here have finished their job.
Methods intended for use in your custom functions
- protected function getPdbFile()
- This function will download the pdb file from wikipdb, and return it as a string.
- protected function getPdbFileArray()
- The same as above, but returns an array of lines in the file.
- protected function callApiDetails( $pluginId )
- Invokes apiDetails action for another plug-in, and returns the result as a string. If the plug-in returns a json encoded array, use the json_decode() php function to decode the result into a class or array.
- $pluginId: The ID of the plug-in invoked. Please include this id into the conditions list of the constructor.
- protected function callUserAction( $pluginId, $userAction )
- Invokes a userAction action for another plug-in, and returns the result as a string.
- $pluginId - The ID of the plug-in invoked. Please include this id into the conditions list of the constructor.
- $userAction - The name of the action that is being invoked.
Methods that should be written by the developer of the plug-in
- abstract protected function userDefinedErrorcheck()
- Invoked by kick(), This function should contain the error check algorithm.
- abstract protected function help()
- This function should return a human readable help file in HTML format, that gives information about the plug-in for WikiPDB endusers
- abstract protected function details()
- This function should return human readable list of errors in HTML format. Intended for WikiPDB endusers
- abstract protected function apiDetails()
- This function should return a list of errors in JSON. Intended for other WikiPDB plug-ins
- protected function useraction()
- This function is invoked, when the action is useraction. Use it any way you see fit.
Methods necessary for the abstract class
These functions should not be called from outside the abstract class.
- protected function start()
- This Function is invoked when WikiPDB sends a start signal to the plug-in. Returns the plug-in name, and conditions to WikiPDB.
- protected function kick()
- This Function is invoked when WikiPDB sends a kick signal to the plug-in. After basic check on the input values this will call the userDefinedErrorcheck abstract function, which has to be defined by the developer of the plug-in.
- protected function debug()
- This function is for debuging the check algorithm. It is recomended, that you comment it out once you are finished with development.
