1. Introduction
This manual will show you how to implement an extended version of the generic filesystem connector available to all translationstudio modules.
The connector will allow you to add any number of projects to the connector with their own settings:
-
Job configuration to determine when to start a translation for all pages/datasets using the respective project.
-
A notification email address.
-
Target folder that will contain copies of the translatable xml files.
-
A command that might be executed after the translatable xml files have been created.
Each connector consists of 2 projects:
-
FirstSpirit module to provide the configuration panel.
-
translationstudio JAR library with the connector implementation.
This example connector implementation will assume Netbeans as your IDE.
You will find a Javadoc available at api/javadoc/connector
2. Setup the projects
First, create a FirstSpirit module maven project CONNECTOR - Example - Frontend. You will have to add the translationstudio FSM’s JAR file as dependency to obtain the API necessary to implement this FirstSpirit module.
As part of the FirstSpirit module, you have to add a module-isolated.xml
file. translationstudio uses an auto connector lookup by checking all available modules. Each module, whose public component’s name starts with the prefix TSConnector
will be considered a translationstudio connector and made available to translationstudio.
<module>
<name>myconnector</name>
<displayname>FirstSpirit translationstudio Connector (I,L)</displayname>
<version>${project.version}</version>
<vendor>${vendor}</vendor>
<description>FS5.2 Module ${name}</description>
<components>
<public>
<name>TSConnector myconnector</name>
<displayname>myconnector</displayname>
<class>com.idmedia.translationstudio.connector.example.configuration.Connector</class>
<resources>
<resource scope="module" name="${project.groupId}:${project.artifactId}" version="${project.version}" minVersion="${project.version}" mode="isolated">lib/${project.artifactId}-${project.version}.jar</resource>
</resources>
</public>
</components>
</module>
Second, create a Connector maven project CONNECTOR - Example - Backend.The POM files will require you to add the following dependencies to your projects:
-
FirstSpirit access JAR (from your FirstSpirit installation).
-
translationstudio Connector API jar (from your translationstudio
./lib
folder).
3. Implementation - CONNECTOR - Example - Frontend
Open the newly created project CONNECTOR - Example - Frontend and create a new class Connector
that implements com.idmedia.translationstudio.api.connector.gui.ItranslationstudioConnector
@Override
public String getInstanceClass()
{
/** this is the full qualified class name of the actual backend
connector implementation. A new instance will be created using
java reflections. */
return "com.idmedia.translationstudio.testautomation.connector.Connector";
}
@Override
public ITranslatioStudioConnectorGui getGui()
{
return new TranslatioStudioConnectorGuiImpl();
}
Now, create a new class TranslatioStudioConnectorGuiImpl
which implements com.idmedia.translationstudio.api.connector.gui.ITranslatioStudioConnectorGui
. This
The actual connector configuration panel can be provided by creating a new JPanel
class and providing this via the method public JPanel getConfigurationPanel()
.
3.1. Understanding the configuration
A connector basically contains 2 types of configuration:
-
The configuration necessary to restore the conplete configuration panel (including some labels, displaynames etc.)
-
The configuration required by the connector implementation to perform its tasks (usually, this configuration is much smaller than the connector configuration panel’s configuration).
@Override
public String getGuiConfiguration()
{
/** this data will only be available to the FSM */
return "";
}
@Override
public String getConnectorConfiguration()
{
/** this data will be transferred to your backend connector implementation 'as is'. */
return "";
}
3.2. Initialising the panel
Since this panel will now be accessible, we need to add a method to initialise it once it has been created.
Therefore, add the following method and ignore potential errors for the moment:
/**
* Init the panel right after it is being displayed
* @param sId The ID of this connector provided by translationstudio. Do not change this!
* @param sConfiguration Configuration as provided by onSaveGuiConfiguration()
* @param vpQuotas List of available quota configurations (always has at least 1 entry, the "default" quota)
* @param pCommunicator Object to send custom messages to your backend connector instance
*/
public void onInit(String sId, String sConfiguration, List<IProjectJobConfigurtion> vpQuotas, IExchangeCommunicator pCommunicator)
{
/** init your JPanel based on the configuration data provided by sXml */
}
3.3. Creating a list of configured projects
Finally, we have to provide a list of configured projects ready to be used by translationstudio and in your language mappings in your FirstSpirit project.
You will need to provide at least 1 valid object for the connector to be available. |
Therefore, add the following method:
/**
* Create a list of configured projects that will be used by translationstudio and eventually made available
* to the language mappings dropdown component.
* @return
*/
@NotNull
List<IConfiguredTranslationMemoryProject> getConfiguredProjects()
{
final List<IConfiguredTranslationMemoryProject> vpList = new ArrayList<>();
/*
* @TODO: Provide at least 1 configured project to use this connector.
*/
return vpList;
}
4. Implementation - CONNECTOR - Example - Backend
Open the newly created project CONNECTOR - Example - Backend.
This project will provide the business logic of the connector.
You can access the entire translationstudio API via |
Create a new class com.idmedia.translationstudio.connector.example.impl.Connector
implementing ITranslationMemoryConnector
This class has to match your return value as given in the FSMs |
A connector has three tasks to perform:
/**
* Operation to transfer files into the TMS
* @return
*/
public ITranslationOperation getTranslationOperation();
/**
* Operation to query for finished translations
* @return
*/
public ITranslationStatusQueryOperation getTranslationStatusQueryOperation();
/**
* Operation to manage queries from the connector's configuration panel (ServerManager)
* @param sQueryData Input data
* @return
*/
public IQueryOperation getQueryOperation(String sQueryData);
Each of the first two operations will be requested from translationstudio after the setup method has been called:
/**
* Setup the connector
*
* @param sTmsId Tms Id
* @param sConfigurationXml Connector Configuration (as provided by {@link com.idmedia.translationstudio.api.connector.gui.ITranslationMemorySystemConnectorConfigurationGui.getConnectorConfiguration}
* @param sWorkingDirectory Connector Working Directory
* @param pContext Connector Context
* @return
*/
public boolean setup(String sTmsId, String sConfigurationXml, String sWorkingDirectory, IConnectorContext pContext);
There are 2 essential parameters:
-
sConfigurationXml
This parameter provides the exact String provided by the connector configuration implementation ofITranslationMemorySystemConnectorConfigurationGui.getConnectorConfiguration()
-
pContext
This parameter provides an access point to the translationstudio API
In addition, you may react to any changes to your connector configuration (i.e. whenever the configuration has been updated using translationstudio’s configuration panel):
/**
* Method called when the settings are updated using the ServerManager
* @param sConfigurationXml Connector Configuration (as provided by {@link com.idmedia.translationstudio.api.connector.gui.ITranslationMemorySystemConnectorConfigurationGui.getConnectorConfiguration}
*/
public void onUpdateConfiguration(String sConfigurationXml);
4.1. Setting it all up
Your implementation of the setup method has to evaluate the xml provided by the connector configuration panel.
Since this is simple XML evaluation, I leave this up to you. However, you have to store the result in a member variable, for example:
/**
* Hold the configuration
*/
private final Configuration m_pConfiguration = new Configuration();
/**
* {@inheritDoc }
*/
@Override
public boolean setup(String sTmsId, String sConfigurationXml, String sWorkingDirectory, IConnectorContext pContext)
{
m_pConfiguration.load(sConfigurationXml);
return true;
}
4.2. Giving away the name and version
We do not want to be shy so there is no need to hide the name and version of this wonderful connector:
/**
* {@inheritDoc }
*/
@Override
public String getName()
{
return "Extended Filesystem Connector";
}
/**
* {@inheritDoc }
*/
@Override
public String getVersion()
{
return "2.3.0"; /* I am lazy, so I simply use the translationstudio Version */
}
4.3. Adding operations
The three operations will be implemented in their own classes, so it will be easy here:
/**
* {@inheritDoc }
*/
@Override
public ITranslationOperation getTranslationOperation()
{
return new TranslationOperation(m_pConfiguration);
}
/**
* {@inheritDoc }
*/
@Override
public ITranslationStatusQueryOperation getTranslationStatusQueryOperation()
{
return new TranslationStatusQueryOperation();
}
/**
* {@inheritDoc }
*/
@Override
public IQueryOperation getQueryOperation(String sQueryData)
{
return new QueryOperation();
}
4.4. Reacting to configuration changes
This connector does not need to react to configuration changes. However, if your connector wants provide a web interface which has to connect to a third party system, you may want to use this method to store the configuration in your own configuration file. This file may, in turn, be loaded by the web interface when required. For now, we do not need it.
/**
* {@inheritDoc }
*/
@Override
public void onUpdateConfiguration(String sConfigurationXml)
{
/* not needed */
}
4.5. Performing additional tasks.
It is possible to perform additional tasks after translatable XMLs have been processed using the ITranslationOperation
. This connector, however, does not need this capability.
/**
* {@inheritDoc }
*/
@Override
public void onPerformAdditionalTasks()
{
/* not needed */
}
If you want to check for certain events (i.e. monitoring a folder), this method is the place to implement this particular logic. |
4.6. Interacting with the connector’s configuration panel
The method public IQueryOperation getQueryOperation(String sQueryData)
allows your connector’s configuration panel to query data at runtime. For example, if you connect to a third party system and want to load all available projects and list them in the configuration panel, this method is what you are looking for.
The configuration panel can use the method IExchangeCommunicatorsendMessage(String sMessage, IQueryRequestAnswerReceived pOnAnswerCallback);
to send a message to an instance of this connector.
The setup method will not be called. All data necessary to setup the connector have to be sent in the message itself (i.e. credentials etc.). |
This connector does not need such a feature, so we use an empty implementation:
/**
* Do nothing
*/
private static class QueryOperation implements IQueryOperation
{
/**
* {@inheritDoc }
*/
@Override
public void query()
{
}
/**
* {@inheritDoc }
*/
@NotNull
@Override
public String getResult()
{
return "";
}
}
4.7. Processing translatable XMLs
Whenever your connector has to handle new translatable XMLs, an instance of the ITranslationOperation
is requested.
First, all candidate XML files to be sent will be added to the instance.
/**
* {@inheritDoc }
*/
@Override
public void addTranslatableFiles(List<ITranslatableFilegt; vpList)
{
/**
* @TODO: store in a list
*/
}
Once all translatable xml files have been added to the operation will be executed:
/**
* {@inheritDoc }
*/
@Override
public boolean perform()
{
boolean bSuccess = true;
/**
* @TODO: do something with the XML files
*/
return bSuccess;
}
If you want translationstudio to check for finished translations using your connector, you have to provide a list of IDs that will be used to do this.
Depending on your implementation, you may provide an ID for each XML file or one ID per translation "project". It does not matter to translationstudio, because your connector needs to handle the status query etc. and it has to be able to obtain all relevant data via these IDs.
@Override
public List<ITransferedFile> getResult()
{
/**
* @TODO: provide actual elements
*/
return Collections.emptyList();
}
If you do not want to check particular IDs but a folder, you may want to implement that logic in the Connector’s |
4.8. Monitoring the translation status
translationstudio will check the translation status of all transferred files regularly. Your connector has to implement ITranslationStatusQueryOperation
to do this.
class TranslationStatusQueryOperation implements ITranslationStatusQueryOperation
{
/**
* Get translated data from the TMS
* @param pFile File Data
* @param pOutputStream
* @return success state
*/
@Nullable
public boolean downloadTranslation(@NotNull TMSFile pFile, @NotNull IStorableFileStream pOutputStream)
{
/*
* Download the data from the target system. IDs are provided via pFile
* Simply write the data to the output stream object.
* The data will only be kept, if this method returns successfully.
*/
}
/**
* Add file status to be queried
* @param pFileData File Data to lookup in the TMS
*/
public void addFileToMonitor(@NotNull IFileStatus pFileData)
{
/*
* All files to be monitored will be added via this method.
*/
}
/**
* perform operation
*
* @return true, if the result is OK, and FALSE will cause the lookup result to be ignored entirely (e.g. some IOExeption etc.).
*/
public boolean query()
{
/*
* Check the status of each file provided.
*/
}
}
You can update the translation status of a file checked in the query
method by calling the method IFileStatus.setStatus(…)
.
The initial status of each file to monitor is |