Skip to content
Snippets Groups Projects
Commit a4460d9e authored by Marco Del Tufo's avatar Marco Del Tufo
Browse files

Update as-api-listener.md

parent c655e3bf
No related branches found
No related tags found
1 merge request!40SSDM-13578 : 2PT : Database and V3 Implementation - include the new AFS "free"...
...@@ -3,69 +3,51 @@ ...@@ -3,69 +3,51 @@
Introduction Introduction
------------ ------------
The V3 API listener core plugin is an implementation of the interceptor The V3 API listener core plugin is an implementation of the interceptor pattern: `<https://en.wikipedia.org/wiki/Interceptor_pattern>`
pattern: <https://en.wikipedia.org/wiki/Interceptor_pattern>
It actually intercepts twice, right before an operation is executed, and It actually intercepts twice, right before an operation is executed, and right after.
right after.
![image info](img/122.png) ![image info](img/122.png)
Its main focus is to help integrations. It gives an opportunity to Its main focus is to help integrations. It gives an opportunity to integrators to execute additional functionality before or after an api call with the next purposes:
integrators to execute additional functionality before or after an api
call with the next purposes:
- Modify the API call inputs/outputs immediately before/after they - Modify the API call inputs/outputs immediately before/after they reach its executor.
reach its executor. - Trigger additional internal logic.
- Trigger additional internal logic. - Notify third party systems.
- Notify third party systems.
Core Plugin Core Plugin
----------- -----------
To archive these goals is necessary to provide a core plugin of the type To archive these goals is necessary to provide a core plugin of the type 'api-listener' to the AS:
'api-listener' to the AS:
### Plugin.properties ### Plugin.properties
It is required to provide an 'operation-listener.class' indicating the It is required to provide an 'operation-listener.class' indicating the class name of the listener that will be loaded.
class name of the listener that will be loaded.
Additionally any number of properties following the Additionally any number of properties following the pattern `operation-listener.<your-custom-name>` can be provided. Custom properties are provided to help maintainability, they give an opportunity to the integrator to only need to compile the listener once and configure it differently for different instances.
pattern 'operation-listener.<your-custom-name>' can be provided.
Custom properties are provided to help maintainability, they give an
opportunity to the integrator to only need to compile the listener once
and configure it differently for different instances.
**plugin.properties** **plugin.properties**
operation-listener.class = ch.ethz.sis.openbis.generic.server.asapi.v3.executor.operation.OperationListenerExample ```
operation-listener.your-config-property = Your Config Message operation-listener.class = ch.ethz.sis.openbis.generic.server.asapi.v3.executor.operation.OperationListenerExample
operation-listener.your-config-property = Your Config Message
```
### lib ### lib
The core plugin should contain a lib folder with a jar containing a The core plugin should contain a lib folder with a jar containing a class that implements the interface IOperationListener, this interface is provided with the V3 API jar and provides 3 methods:
class that implements the interface IOperationListener, this interface
is provided with the V3 API jar and provides 3 methods:
- setup: Runs on startup. Gives one opportunity to read the - setup: Runs on startup. Gives one opportunity to read the configuration provided to the core plugin
configuration provided to the core plugin - beforeOperation: Runs before each operation occurs. In addition to the operation intercepted it also provides access to the api and the session token used for the operation.
- beforeOperation: Runs before each operation occurs. In addition to - afterOperation: Intercepts after the operation occurs. In addition to the operation intercepted it also provides access to the api, the session token used for the operation, the operation result and any exception that happened during the operation.
the operation intercepted it also provides access to the api and the
session token used for the operation.
- afterOperation: Intercepts after the operation occurs. In addition
to the operation intercepted it also provides access to the api, the
session token used for the operation, the operation result and any
exception that happened during the operation.
```{warning} ```{warning}
Implicit Requirements Implicit Requirements
**Requirement 1: The Listener should be Thread Safe Code** **Requirement 1: The Listener should be Thread Safe Code**
A single instance of the Listener is created during the server startup. A single instance of the Listener is created during the server startup. Since a single instance is used to serve all requests thread safe code is a requirement. We strongly suggest to not to keep any state.
Since a single instance is used to serve all requests thread safe code is a requirement.
We strongly suggest to not to keep any state.
**Requirement 2: The Listener should not throw Exceptions** **Requirement 2: The Listener should not throw Exceptions**
...@@ -78,73 +60,76 @@ All API Operations go through every listener so the method signatures should use ...@@ -78,73 +60,76 @@ All API Operations go through every listener so the method signatures should use
**IOperationListener** **IOperationListener**
package ch.ethz.sis.openbis.generic.asapi.v3.plugin.listener; ```java
package ch.ethz.sis.openbis.generic.asapi.v3.plugin.listener;
import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi;
import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.operation.IOperation;
import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.operation.IOperationResult;
import java.util.Properties;
public interface IOperationListener<OPERATION extends IOperation, RESULT extends IOperationResult>
{
public static final String LISTENER_PROPERTY_KEY = "operation-listener";
public static final String LISTENER_CLASS_KEY = LISTENER_PROPERTY_KEY + ".class";
public abstract void setup(Properties properties);
public abstract void beforeOperation(IApplicationServerApi api, String sessionToken, OPERATION operation);
public abstract void afterOperation(IApplicationServerApi api, String sessionToken, OPERATION operation,
RESULT result, RuntimeException runtimeException);
}
```
import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi;
import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.operation.IOperation;
import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.operation.IOperationResult;
import java.util.Properties;
public interface IOperationListener<OPERATION extends IOperation, RESULT extends IOperationResult>
{
public static final String LISTENER_PROPERTY_KEY = "operation-listener";
public static final String LISTENER_CLASS_KEY = LISTENER_PROPERTY_KEY + ".class";
public abstract void setup(Properties properties);
public abstract void beforeOperation(IApplicationServerApi api, String sessionToken, OPERATION operation);
public abstract void afterOperation(IApplicationServerApi api, String sessionToken, OPERATION operation,
RESULT result, RuntimeException runtimeException);
}
### Example - Logging ### Example - Logging
The next implementation example captures the calls and logs on the The next implementation example captures the calls and logs on the standard openbis log the operation name:
standard openbis log the operation name:
**OperationListenerExample** **OperationListenerExample**
package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.operation; ```java
package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.operation;
import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi;
import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.operation.IOperation;
import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.operation.IOperationResult;
import ch.ethz.sis.openbis.generic.asapi.v3.plugin.listener.IOperationListener;
import ch.systemsx.cisd.common.logging.LogCategory;
import ch.systemsx.cisd.common.logging.LogFactory;
import org.apache.log4j.Logger;
import java.util.Properties;
import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; public class OperationListenerExample implements IOperationListener<IOperation, IOperationResult>
import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.operation.IOperation; {
import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.operation.IOperationResult;
import ch.ethz.sis.openbis.generic.asapi.v3.plugin.listener.IOperationListener;
import ch.systemsx.cisd.common.logging.LogCategory;
import ch.systemsx.cisd.common.logging.LogFactory;
import org.apache.log4j.Logger;
import java.util.Properties; private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
OperationListenerExample.class);
public class OperationListenerExample implements IOperationListener<IOperation, IOperationResult> private String yourConfigProperty = null;
@Override
public void setup(Properties properties)
{
yourConfigProperty = properties.getProperty("operation-listener.your-config-property");
operationLog.info("setup: " + yourConfigProperty);
}
@Override
public void beforeOperation(IApplicationServerApi api, String sessionToken, IOperation operation)
{ {
operationLog.info("beforeOperation: " + operation.getClass().getSimpleName());
}
private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, @Override
OperationListenerExample.class); public void afterOperation(IApplicationServerApi api, String sessionToken, IOperation operation,
IOperationResult result, RuntimeException runtimeException)
private String yourConfigProperty = null; {
operationLog.info("afterOperation: " + operation.getClass().getSimpleName());
@Override
public void setup(Properties properties)
{
yourConfigProperty = properties.getProperty("operation-listener.your-config-property");
operationLog.info("setup: " + yourConfigProperty);
}
@Override
public void beforeOperation(IApplicationServerApi api, String sessionToken, IOperation operation)
{
operationLog.info("beforeOperation: " + operation.getClass().getSimpleName());
}
@Override
public void afterOperation(IApplicationServerApi api, String sessionToken, IOperation operation,
IOperationResult result, RuntimeException runtimeException)
{
operationLog.info("afterOperation: " + operation.getClass().getSimpleName());
}
} }
}
```
### Example - Loggin Sources ### Example - Loggin Sources
You can download a complete example with sources You can download a complete example with sources [here](/download/attachments/132286253/api-listener-example.zip?version=1&modificationDate=1663665058217&api=v2) to use as a template to make your own.
[here](/download/attachments/132286253/api-listener-example.zip?version=1&modificationDate=1663665058217&api=v2) to
use as a template to make your own.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment