Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
472 lines (373 sloc) 19.6 KB

Beyond just files: Using PLM for versioning and metadata

This document describes how to use PLM services from inside a service, i.e., by calling the PLM API. The text includes example code. There are two types of PLM services for use in CAxMan; both are described below:

  1. those that are integrated in the GSS framework;
  2. the PLM Server native web-services.

PLM API through GSS

The PLM server has features which go beyond what is offered by the GSS service. In order to use these additional features, a PLM service endpoint needs to be obtained (use the getDirectionInteractionEndpoint() method of GSS)

Some of the PLM functionality is available as an extension to the GSS service in the sense that the implementation is similarly structured as the GSS service and accepts the same GSS-specific arguments. The remaining PLM Server functionality is only available as native PLM Server SOAP web-services; see below for details.

Java (Maven) client based examples can be retrieved from here: https://github.com/CAxMan/PlmGSS-samples

Code samples of extension to the GSS service: https://github.com/CAxMan/infrastructureClients

The PLM-only GSS extension comprises the following SOAP methods:

  • createFolderVersion
  • listFolderVersions
  • listFileVersions
  • plm2gss
  • gss2plm
  • getFileVersion
  • getHostingFolder

createFolderVersion - creates a new version of the specified folder. Children folders of the existing selected version are reused; files are copied. Parameters:

  • folderID - GSS folder id of the folder to create the new version from. Example: plm://InitialRepository/Ultralight_Glider/236223201541
  • session_id - Keystone authentication token Returns: GSS folder ID of the newly created folder version

listFolderVersions - lists all versions of the specified folder including the one specified. Parameters:

  • path - GSS folder id. Example: plm://InitialRepository/Ultralight_Glider/236223201541
  • session_id - Keystone authentication token Returns: ResourceInformation object for each folder version

listFileVersions - lists all versions of the specified file including the one specified. Parameters:

  • path - GSS file id. Example: plm://InitialRepository/Ultralight_Glider/236223201541
  • session_id - Keystone authentication token Returns: ResourceInformation object for each file version

Note that the above methods can technically accept any kind of GSS URI (which is represented as a mere string in CAxMan), but the methods will obviously fail when non-PLM URIs are provided.

The following two methods can be used to switch between PLM-specific GSS URIs and PLM native id. PLM-specific GSS URIs look like the following. "plm://TestRepository/MyModel123/1234567890" where the last part (integer value) is a native PLM object identifier.

plm2gss - converts a PLM object identifier to a GSS identifier

Example:

String keystoneToken = ...
V_node node = ...
ResourceInformation folderId = srv.plm2Gss(node.getNodus().getItem().getInstance_id(), keystoneToken);
String id = folderId.getUniqueName();

gss2plm - converts a GSS identifier to PLM object identifier

Example:

String keystoneToken = ...
FileWebService_PortType srv = new FileWebService_ServiceLocator().getFileWebServicePort();
PlmResource plmId = srv.gss2Plm("plm://TestRepository/MyModel123/1234567890", keystoneToken);

String wsdl = plmId.getWsdlUrl();
String serviceUrl = plmId.getServiceUrl();

getFileVersion - can be used to retrieve file version, that is, file in a different folder with the same name. Parameters:

  • folderID - GSS id of the new (just created) folder (version). Example: plm://InitialRepository/Ultralight_Glider/236223201541
  • oldFileID GSS id of a file in previous folder version
  • session_id - Keystone authentication token Returns: GSS id of a file version in the given (folderID) folder

getHostingFolder - can be used to retrieve GSS id of a hosting folder by given GSS file id. Parameters:

  • fileId - GSS id of a file. Example: plm://InitialRepository/Ultralight_Glider/236223201541
  • session_id - Keystone authentication token Returns: GSS id of a folder where specified file is located.

PLM API through native services (SOAP)

The remaining and largest share of PLM functionality, that is, for which GSS does not deliver endpoints, is only available for use in CAxMan through PLM Server native services. Note that in order to use this functionality, GSS URIs need to be converted into native PLM object identifiers (see above for converter functions).

Note, all code samples below are in Java. Java classes are generated by "axistools-maven-plugin" (version 1.4) from WSDL documents.

Authentication in PLM database

There is a group of SOAP services (Access) to perform authentication against the PLM Server. WSDL: https://caxman.clesgo.net/jotne/EDMWS/WSDLGenerator?accesscontrol=yes&user=simdm_user&password=db&option=LITERAL_ENCODING

The following methods from the Access group of services may be specifically useful for you.

  • login - to obtain a session identifier that will then be used as a parameter in all other services.
  • logout - to close an existing session. An existing session is closed automatically after 12 hours of no services being called.

Example:

EDMAccessControlServiceLocator edmAccessControlServiceLocator = new EDMAccessControlServiceLocator();
String server = "https://caxman.clesgo.net/jotne";
EDMAccessControl edmAccessControl = edmAccessControlServiceLocator.getEDMWS(new URL(server + "/EDMWS/AccessControl?option=LITERAL_ENCODING"));
...
// login - can be valid Keystone token
// password - any not empty value in case of using valid Keystone token
// Keystone token works if corresponding user name is registered in PLM database
String sessionID = edmAccessControl.login("login", "sdai-group", "password");
...
String closeResult = edmAccessControl.logout(sessionID);

Repositories and models

Another group of services (Config) has methods to handle repositories and models in the PLM Server. WSDL: https://caxman.clesgo.net/jotne/EDMWS/WSDLGenerator?user=simdm_user&password=db&repository=SimDM_system&model=Config&schema=SimDM_config&querySchema=SimDM_config_support&option=LITERAL_ENCODING

Get available repositories and models:

SimDM_config_supportServiceLocator supportServiceLocator = new SimDM_config_supportServiceLocator();
SimDM_config_support configService = supportServiceLocator.getEDMWS();
...
V_repository[] repositories = configService.repository_list(sessionID); // sessionID - session identifier got from login method

Now the required repository can be found by name:

V_repository repo = null;
if (repositories != null) {
   for (V_repository r : repositories) {
       if ("name_you_are_looking".equals(r.getName())) {
           repo = r; // repository is found
           break;
       }
   }
}

A repository may contain many models. A required model can be found by name:

V_model model = null;
V_model[] models = repo.getModels();
if (models != null) {
   for (V_model m : models) {
       if ("name_you_are_looking".equals(m.getName())) {
           model = m; // model is found
           break;
       }
   }
}

Repositories and models can be deleted. Note: To delete a repository all models within that repository must have been deleted first.

configService.delete_model(sessionID, repo.getName(), model.getName(), null);
configService.delete_repository(sessionID, repo.getName());

If a repository or model does not yet exist, it can be created. Note: The repository name shall start with a letter followed by letters, digits and underscore symbols. Repository names are case insensitive; i.e., strings that only differ by their use of uppercase and lowercase letters identify the same repository. Model names shall be unique within a repository. Model names follow the same principles as repository names.

V_repository repo = configService.create_repository(sessionID, "repository_name", "description text");
V_model model = configService.create_model(sessionID, repo.getName(), "model_Name", "description text here", "PROJECT"); // "PROJECT" - default value in GSS

Product structure

Another group of services (SimDMMaster) has methods to handle product structure (folders, files, etc.) in the PLM Server. WSDL: https://caxman.clesgo.net/jotne/EDMWS/WSDLGenerator?user=simdm_user&password=db&repository=SimDM_system&model=user_management&schema=SIMDM_MASTER&querySchema=SIMDM_MASTER_WSDL&option=LITERAL_ENCODING

Note, the WSDL above is to work with one specific model in one specific repository. Repository and model names are included in the URL:

  • Repository name: SimDM_system
  • Model name: user_management

The model "user_management" is a special model that is used as a library of available database users.

It is enough to generate client stub classes for one model. Generated classes can be used to work with product structures in different repositories and models.

String server = "https://caxman.clesgo.net/jotne";

String repoName = "TestRepository";
String modelName = "existing_model_name";

String url = String.format("%s/EDMWS/earlybinding/options_2097152/%s/%s/QEX/SIMDM_MASTER_WSDL", server, repoName, modelName);
SIMDM_MASTER_WSDL simDmService = simDmMasterServiceLocator.getEDMWS(new URL(url));

A product structure is defined in the just created model.

V_item item = new V_item();
item.setDescription("");
item.setIntroduced("");
item.setItem_type("PROJECT"); // can be one from list: simDmService.pbs_list_types(sessionID); 
item.setLast_changed("");
item.setName("root"); // Root element. Represents the product structure itself. Files cannot be stored here.
item.setPreview("");

V_nodus nodus = new V_nodus();
nodus.setVersion("");

V_pbs pbsTop = new V_pbs(); // object that represents the Product Structure.
pbsTop.setNodus(nodus);
nodus.setItem(item);
pbsTop = simDmService.pbs_create(sessionID, pbsTop); // pbsTop will obtain additional metadata generated by PLM server

V_pbs object can be considered as a storage for product structure metadata or resources: persons, organizations, approvals, properties, etc.

Just created V_pbs object will have one single person (V_person) for the PLM Server user who executed pbs_create.

Properties

A product structure may include user defined properties. Property values are assigned to folders. Property (property definition) reside in V_pbs object.

Available property (definitions) can be retrieved in the following way:

V_pbs pbsTop = ...
V_property[] properties = simDmService.property_list(sessionID, pbsTop.getProperties());

Property (definitions) can be created like this:

V_item item = new V_item();
item.setItem_type("DOUBLE_PROPERTY"); // possible values can be got from here: simDmService.property_list_types(sessionID);
item.setName("direction");
item.setDescription("...");

V_property property = new V_property();
property.setItem(item);
// folders of what types can have property assignment
property.setApplicable_to(new String[] {"ANALYSIS", "DESIGN"}); // possible values can be got from here: simDmService.node_list_types(sessionID, 0); 
property.setDefault_value(null); // should be set for mandatory properties
// the property describes 3d vector
property.setHigh_dimension(3);
property.setLow_dimension(3);
property.setMandatory(false); // optional property
property.setScalar(false); // property describes vector value
property.setUnits(null);
property = simDmService.property_create(sessionID, property);

Property definitions can be updated or deleted:

  • property_update
  • property_cancel

Note: Property (definitions) can only be deleted completely from a product structure if there is no assignment of a value of that property to any folder. When deleted, properties will be marked as "cancelled", and it will not be possible to make new assignments of that property.

Folder

Product structures can be considered as folder structures. Let's assume V_pbs has already been created, but we do not have folder objects, yet. The first folder must be connected to the V_pbs object.

V_pbs pbsTop = simDmService.pbs_get(sessionID, null);

V_item item = new V_item();
item.setName("folder name");
item.setItem_type("DESIGN"); // can be one from list: simDmService.node_list_types(sessionID, 0 /* the value is not used */);
item.setDescription("description text");
item.setIntroduced("");
item.setLast_changed("");
item.setPreview("");

V_nodus nodus = new V_nodus();
nodus.setItem(item);
nodus.setVersion("1");

V_node node = new V_node();
node.setNodus(nodus);
node.setId("global unique identifier");
node.setRealization("");

long parent = pbsTop.getNodus().getItem().getInstance_id();
node = simDmService.node_create(sessionID, node, new long[]{ parent });

A second folder can be created as child of the first folder. A folder (node) may have multiple parents; this is a first major difference from a normal folder structure.

Folders may have multiple children folders and may have multiple files attached (V_attached_file). When a folder is not needed any more, it can be deleted with all its content.

Folder version

Folders may have multiple versions with different version tags. A new folder version may have the same or different children folders compared to the original folder. Also, the same or different files may be attached to the new folder version.

Let's assume V_pbs was already created before, and it has at least one folder.

V_pbs pbs = ...
V_node[] list = simDmService.node_list(sessionID, pbs.getNodus().getNodes());
V_node node = list[0];

long nodeId = pbs.getNodus().getNodes()[0];
V_node version = simDmService.node_create_version(sessionID, nodeId, "v. 2", true, true, true, true, false, true, false, false, false, null, null, null);

According to the input parameters, above, the new folder version will have the same children folders. That is, children folders will be used by two parent versions simultaneously. Else, the new folder version will have copy of all files; thus, there is no simultaneous use of files.

Handle files

Folder (version) may have multiple files attached. Files can be attached to a specified folder by a sequence of a few methods. Let's suppose we have a file named "ULG_Coarse.stp" somewhere in a local folder.

V_item item = new V_item();
item.setName("ULG_Coarse"); // without file extension
item.setItem_type(""); // item type can be evaluated by PLM Server after content is uploaded.
item.setDescription("");
item.setIntroduced("");
item.setLast_changed("");
item.setPreview("");

V_file fileSpec = new V_file();
fileSpec.setItem(item);
fileSpec.setExtension(".stp"); // file extension
fileSpec.set_interface("Interface specifications"/* any human readable text */);
fileSpec.setOriginal_name("absolute path to ULG_Coarse.stp");
fileSpec.setOriginal_format("file format name"); // can be derived from file name by using System API
fileSpec.setOS("Microsoft Windows"/* any text */);
fileSpec.setProduced_by("EPM Thechnology AS");
fileSpec.setSize(0); // size will be evaluated on server
fileSpec.setOwner(0); // organization id
fileSpec.setCheck_sum("");
fileSpec.setLink("");
fileSpec.setExpress_schema("");
fileSpec.setModel_name("");

fileSpec = simDmService.file_create(sessionID, fileSpec);

Consider the V_file object to be the file storage in the PLM Server.

V_node node = ...
V_file fileSpec = ...

V_attached_file attachedFile = new V_attached_file();
V_item item = new V_item();
item.setItem_type("");
item.setDescription("");
item.setIntroduced("");
item.setLast_changed("");
item.setPreview("");
item.setName("ULG_Coarse.stp"); // file name
item.setDescription("description must be here");
attachedFile.setItem(item);
attachedFile.setDomain(node.getItem().getInstance_id());
attachedFile.setFile(fileSpec.getItem().getInstance_id());

attachedFile = simDmService.attached_file_create(sessionID, attachedFile);

Now the file content needs to be uploaded to a server temporary storage.

FileTransferInfo transferInfo = edmAccessControl.createTemporaryFile(sessionId, "name", ".stp", true);

Object transferInfo has the URL information that is used as target for the POST request:

HttpClient client = new HttpClient();
// URL has not valid symbols. It must be encoded
String encUploadOrDownloadUrl = encodeUrl(transferInfo.getUploadOrDownloadUrl()) + sessionId;

PostMethod pm = new PostMethod(encUploadOrDownloadUrl);
File f = new File("path to ULG_Coarse.stp");
pm.setRequestHeader("Content-Type", "xxx.xxx");
pm.setRequestHeader("Content-Length", "" + f.length());
pm.setRequestEntity(new FileRequestEntity(f));
/* int status = */
client.executeMethod(pm);
/* String response = */
pm.getResponseBodyAsStream();

... where encodeUrl can be implemented in the following way:

String encodeUrl(String url) throws UnsupportedEncodingException {
   String result = null;
   Pattern p = Pattern.compile(".*fileName=([^&]+)&.*");
   Matcher m = p.matcher(url);
   if (!m.matches()) {
      // error in regexp
   } else {
      String fileName = m.group(1);
      String encFileName = URLEncoder.encode(fileName, "ASCII");
      result = url.replace(fileName, encFileName);
   }
   return result;
}

And the final method is to put the file from its temporary storage to the PLM Server database.

V_file fileSpec = ...
FileTransferInfo transferInfo = ...

fileSpec = simDmService.file_body_set(sessionID, fileSpec.getItem().getInstance_id(), fileSpec.getSize(), transferInfo.getFileNameOnServer());

To download a specified file it is extracted from the database to a temporary file on the server.

long instance_id = ...
V_attached_file attachedFile = simDmService.attached_file_get(sessionID, instance_id);
// file name and extension for temporary file do not make any sense in this case
FileTransferInfo transferInfo = edmAccessControl.createTemporaryFile(sessionID, "name", ".ext", false);

simDmService.file_body_get(sessionID, attachedFile.getFile()/* file ID */, transferInfo.getFileNameOnServer());

Then the file can be downloaded using the POST request.

File file = File.createTempFile("ULG_Coarse", ".stp");
file.deleteOnExit();

HttpClient client = new HttpClient();
// URL has not valid symbols. It must be encoded
String encUploadOrDownloadUrl = encodeUrl(transferInfo.getUploadOrDownloadUrl()) + sessionId;

PostMethod pm = new PostMethod(encUploadOrDownloadUrl);
/* int status = */client.executeMethod(pm);
InputStream is = pm.getResponseBodyAsStream();
OutputStream os = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while ((len = is.read(buf)) > 0) {
    os.write(buf, 0, len);
}
is.close();
os.close();

Assign property value

Folders may have multiple assigned properties, that is, property values may be assigned to a folder. There can be only a single value of a specific property (definition) assigned to a specific folder.

V_property property = ...
V_node node = ...

V_assigned_property ass = new V_assigned_property();
ass.setItem(new V_item());
ass.setDomain(parentNode.getNodus().getItem().getInstance_id());
ass.setAssignment(property.getItem().getInstance_id());
ass.setValues(new String[] {"1.23", "3.45", "0.0"}); // vector of three string values. each represents double value
        
ass = simDmService.assigned_property_create(sessionID, ass);
You can’t perform that action at this time.