HostingProgrammersGuide PDF

Download as pdf or txt
Download as pdf or txt
You are on page 1of 38

SIEMENS

Active Workspace
Hosting
Programmers Guide
AW • 2.4
Active Workspace Hosting Programmers Guide – V2.4

Active Workspace Hosting Programmers Guide


Contents

1. Introduction .......................................................................................................................................... 3
Terms and Definitions ............................................................................................................................... 3
Exported Libraries ..................................................................................................................................... 4
Java (Platform Neutral) ......................................................................................................................... 4
C++ (Win32/Win64) .............................................................................................................................. 4
C++ (Linux/gcc) ...................................................................................................................................... 4
C++ (Mac/clang) .................................................................................................................................... 4
C# (Win32/Win64) ................................................................................................................................ 4
JavaScript .............................................................................................................................................. 4
External Dependencies ............................................................................................................................. 5
Java........................................................................................................................................................ 5
C# .......................................................................................................................................................... 5
Javascript............................................................................................................................................... 5
C++ ........................................................................................................................................................ 5
Message Path Overview............................................................................................................................ 6
2. How to Host Active Workspace ............................................................................................................ 8
Java............................................................................................................................................................ 9
C++ ............................................................................................................................................................ 9
JavaScript ................................................................................................................................................ 10
3. Existing Hosting Services ..................................................................................................................... 11
Host-Side Services ................................................................................................................................... 12
SOA Related ‘Infrastructure’ Services ................................................................................................. 12
General ‘Infrastructure’ Services ........................................................................................................ 12
General ‘Solutions’ Services ................................................................................................................ 13
Client-Side Services ................................................................................................................................. 14
SOA Related ‘Infrastructure’ Services ................................................................................................. 14
General ‘Infrastructure’ Services ........................................................................................................ 14
General ‘Solutions’ Services ................................................................................................................ 14

Siemens PLM Software - Confidential Page 1


Active Workspace Hosting Programmers Guide – V2.4

4. Invoking Proxies .................................................................................................................................. 16


Java...................................................................................................................................................... 16
C++ ...................................................................................................................................................... 16
JavaScript ............................................................................................................................................ 16
5. How to Write a Proxy .......................................................................................................................... 17
Java...................................................................................................................................................... 18
C++ ...................................................................................................................................................... 18
JavaScript ............................................................................................................................................ 19
Proxy Messages....................................................................................................................................... 19
Java...................................................................................................................................................... 20
C++ ...................................................................................................................................................... 20
JavaScript ............................................................................................................................................ 20
6. How to Write a Service ....................................................................................................................... 21
Java...................................................................................................................................................... 22
JavaScript ............................................................................................................................................ 22
7. Hosting a Component ......................................................................................................................... 23
Component Example URLs ...................................................................................................................... 23
Service Details ..................................................................................................................................... 23
C++ ...................................................................................................................................................... 25
8. Handshake Phase State Diagram ........................................................................................................ 28
9. Active Workspace URLs....................................................................................................................... 30
10. Global Methods in Browser ............................................................................................................ 31
11. Trouble Shooting ............................................................................................................................. 32
I'm having trouble connecting ............................................................................................................ 32
I'm having trouble with a service ........................................................................................................ 32
I'm still having trouble ........................................................................................................................ 32
12. Example #1 - Javascript - "Hello Hosting" ....................................................................................... 33
Deployment Structure ............................................................................................................................ 33
Html (tests/index.html)........................................................................................................................... 33
Javascript (tests/js/helloHosting.js) ........................................................................................................ 34

Siemens PLM Software - Confidential Page 2


Active Workspace Hosting Programmers Guide – V2.4

1. Introduction
Use the APIs described in this document to host the Active Workspace (AW) client, which includes the
following independent players:

Definition and use of the ‘Interop Libraries’ middleware is the focus of this document.

Terms and Definitions


Host – Application that contains the client application running in one or more instances.

Client – Application that is contained within another (host) application.

Service – Implementation of functionality that extends across the host/client boundary. A service is
called by a proxy from the other side. Services can exist on either side of the boundary.

Proxy – The calling side of a service.

HostControlInstance – Provides support for communication to a specific instance of a hosted client.


Tracks the services provided by both the client and the host.

HostManager – Contains all the known host services.

Fully Qualified Name (FQN) – The name of a service. This name must be known to both the host and
client, and is used to connect proxies to services. For services that exist on the host-side, the suffix
“.host” is used. For services that exist on the client the suffix “.client” is used.

Target Service Descriptor – Combination of the Fully Qualified Name and a version number.

Event – An asynchronous call into a service, which doesn't return a result.

Method – A synchronous call into a service, which returns a result.

Host Content State – The current state of the host instance. Used to track whether the client is capable
of communication and, if it is, what type of communication it’s capable of.

Component – A functional unit of Active Workspace that can be hosted as a standalone web application.
An example is the ObjectInfo component which displays summary data about an object.

Active Workspace (AW) - A client application that is the focus of many services and examples in this
programmer guide.

Siemens PLM Software - Confidential Page 3


Active Workspace Hosting Programmers Guide – V2.4

Exported Libraries
Hosting APIs are provided via the following language bindings:

 Java
 C++
 C# (.net)
 JavaScript

The specific libraries for the various language bindings and operating systems are as follows.

Java (Platform Neutral)


com.siemens.splm.browserinterop.infrastucture.jar
com.siemens.splm.browserinterop.solutions.jar

C++ (Win32/Win64)
libweb_hosting.dll
libweb_hosting.lib
libweb_hostingservices.dll
libweb_hostingservices.lib

C++ (Linux/gcc)
libweb_hosting.so
libweb_hostingservices.so

C++ (Mac/clang)
libweb_hosting.dylib
libweb_hostingservices.dylib

C# (Win32/Win64)
HostingServices.dll
HostingServices.pdb
HostingSetvices.xml
WpfWebContentHosting.dll
WpfWebContentHosting.pdb
WpfWebContentHosting.xml

JavaScript
splmBrowserInterOp.js
splmBrowserInterOpMin.js (same, only 'minified')

Siemens PLM Software - Confidential Page 4


Active Workspace Hosting Programmers Guide – V2.4

External Dependencies
This is a short list of the external third party libraries the hosting libraries are dependent on.

Java
Google GSON – 2.2.2 - gson2.2.2.jar - Toolbox
SWT - 3.8 – org.eclipse.* - Toolbox
Log4j - 1.2.13 - log4j.jar - Toolbox

C#
Log4j - 1.2.10.0 - log4net.dll - Toolbox

Javascript
None

C++
Log4j - 1.2.10.0 - Toolbox

Siemens PLM Software - Confidential Page 5


Active Workspace Hosting Programmers Guide – V2.4

Message Path Overview

Siemens PLM Software - Confidential Page 6


Active Workspace Hosting Programmers Guide – V2.4

Setup Instructions
This section identifies the general setup instructions for each type of host application. Setting up a host
to encapsulate Active Workspace content typically follows these general steps:

1) Install the Host application.


2) Install Active Workspace on the company's network (assumed here to be at IP address
111.222.333.444 and port 7001).
3) Register the Active Workspace instance URL with specific host applications by setting one or
more of the following Teamcenter preferences (a.k.a. 'options'):

ActiveWorkspaceHosting.NX.URL=http://111.222.333.444:7001/awc
ActiveWorkspaceHosting.Office.URL=http://111.222.333.444:7001/awc
ActiveWorkspaceHosting.RAC.URL=http://111.222.333.444:7001/awc
ActiveWorkspaceHosting.WorkflowEmail.URL=http://111.222.333.444:7001/awc
ActiveWorkspaceHosting.Vis.URL=<not correct today>

Or you can turn on AW client in all host applications by setting the following option:

ActiveWorkspaceHosting.URL=http://111.222.333.444:7001/awc

The Rich Application Client (RAC) has additional options that can be set to allow the Active Workspace UI
to be used instead of the RAC's native UI. Specifically, you can replace the 'My Worklist' (a.k.a. 'Inbox')
and 'Summary' views with the Active Workspace UI by setting the following options:

TC_Use_ActiveWorkspace_Inbox=true
TC_Use_ActiveWorkspace_Summary=true

Siemens PLM Software - Confidential Page 7


Active Workspace Hosting Programmers Guide – V2.4

2. How to Host Active Workspace


There are four main steps to hosting Active Workspace client content. After these steps, the host
application is able to invoke services on the client as well as respond to calls made by the client back to
the host.

A basic overview of the common setup steps are:

1) Add the needed libraries to the host application based on its language binding.
2) Initialize the HostManager singleton instance.
3) Create the WebHostControl object (Java, C++ and C# only).
4) Set the URI of the client into the WebHostControl (or related <iframe>, in the case of
JavaScript)

Here are the steps again with a little more details.

1) Link to the libraries for your language. All libraries are published to the toolbox. See Exported
Libraries for language-specific library details.
2) Initialize the HostManager. This is done by getting an instance of the HostManager singleton
and registering the host-side services you're interested in exposing to the client.

Note: For the Java, C++, and C# bindings the host-side StartupNotificationSvc is required to
assure proper asynchronous operation between the host and client during the 'handshake' phase
that takes place during later steps. For Javascript, this service is not required since it is assumed the
host and client are running inside the same web browser.

3) Create the WebHostControl object. This will contain the embedded browser window and
instantiate the HostControlInstance object used to handle all host-client communication.
4) Pass the URI that contains the location of the client application you wish to host. The URI must
include the ah=true query. This query indicates to the Active Workspace client that it is being
hosted and will cause it to attempt a 'handshake' with the host application before displaying any
of its UI.

Here are language-specific examples of steps 2-4:

Siemens PLM Software - Confidential Page 8


Active Workspace Hosting Programmers Guide – V2.4

Java
import com.siemens.splm.browserinterop.infrastructure.interop.IHostManager;
import com.siemens.splm.browserinterop.infrastructure.interop.IHostServiceDescriptor;
import com.siemens.splm.browserinterop.infrastructure.interop.HostManager;
import com.siemens.splm.browserinterop.infrastructure.services.core._2014_02.StartupNotificationSvc;
import com.siemens.splm.browserinterop.infrastructure.services.logging._2014_02.LoggerForwardSvc;
import com.siemens.splm.browserinterop.solutions.services.selection._2014_02.SelectionProviderSvc;
...
// Step 2
IHostManager hostMgr = HostManager.getTheInstance();
List<IHostServiceDescriptor> hostServices = hostMgr.getKnownServices();
if( hostServices == null || hostServices.isEmpty() )
{
try
{
hostMgr.registerService( new StartupNotificationSvc() );
hostMgr.registerService( new LoggerForwardSvc( new LogEntryHandler() ) );
hostMgr.registerService( new
com.siemens.splm.browserinterop.infrastructure.services.core._2014_07.HostConfigurationSvc(
new sampleawapp._2014_07.HostConfigurationHandler() ) );
hostMgr.registerService( new
com.siemens.splm.browserinterop.infrastructure.services.core._2014_02.HostConfigurationSvc(
new sampleawapp._2014_02.HostConfigurationHandler() ) );
hostMgr.registerService( new SelectionProviderSvc() );
}
catch( Exception ex )
{
}
}
// Step 3
m_webHostControl = new WebHostControl( parentComposite, SWT.NONE );
// Step 4
final TargetConfig uri = new TargetConfig("", "", new URI(http://myhostwebsite.com/tc.html?ah=true));
final IHostControlInstance hostControl = m_webHostControl.getHostInstanceData();

hostControl.launchToTarget(uri);

C++
/* Step 2 */
BROWSERINTEROP_INTEROP_NS::HostManager* hostMgr = BROWSERINTEROP_INTEROP_NS::HostManager::TheInstance();
BROWSERINTEROP_INTEROP_NS::HostServiceList* hostServices = hostMgr->KnownServices();
if( hostServices == NULL || hostServices.GetSize() == 0 )
{
hostMgr->RegisterService(new BROWSERINTEROP_SERVICES_NS::Core::_2014_02::StartupNotificationSvc());

hostMgr->RegisterService(new
BROWSERINTEROP_SERVICES_NS::Logging::_2014_02::LoggerForwardSvc(&SampleWebApp::LogUtilities::logCallback));

hostMgr->RegisterService(new BROWSERINTEROP_SERVICES_NS::Core::_2014_07::HostConfigurationSvc(
new SampleWebApp::2014_07::HostConfigurationHandler());

hostMgr->RegisterService(new BROWSERINTEROP_SERVICES_NS::Core::_2014_02::HostConfigurationSvc(
new SampleWebApp::2014_02::HostConfigurationHandler());

hostMgr->RegisterService(new BROWSERINTEROP_SOLUTIONS_SERVICES_NS::Selection::_2014_07::SelectionProviderSvc());
}
/* Step 3 */
(Creation of the C++ WebControl is Specific to each host)
/* Step 4 */
const std::string& uri("http://myhostwebsite.com/tc.html?ah=true");

Siemens PLM Software - Confidential Page 9


Active Workspace Hosting Programmers Guide – V2.4

BROWSERINTEROP_INTEROP_NS::TargetConfig* targetConfig("","",uri);
m_hostControlInstance->LaunchToTarget(targetConfig);

JavaScript
var clientIFrame = document.getElementById("MyClientIFrame");

// Step 2
var hostManager = INF_INTEROP_HOST_MANAGER.getTheInstance();
var hostServices = hostManager.getKnownServices();
if( hostServices || hostServices.length == 0 ) {
var hostControl = hostManager.initializeHostIntegration(clientIFrame, function (hostManager) {
hostManager.registerService(new INF_SERVICES_LOGGING_2014_02.LoggerForwardSvc( new MyLogEntryHandler());

hostManager.registerService(new INF_SERVICES_CORE_2014_07.HostConfigurationSvc(
new MyHostConfigHandler2014_07());

hostManager.registerService(new INF_SERVICES_CORE_2014_02.HostConfigurationSvc(
new MyHostConfigHandler2014_02());

hostManager.registerService(new SOL_SERVICES_SELECTION_2014_02.SelectionProviderSvc();
}
}
// Step 3 - N/A
// Step 4
clientIFrame.src = "http://myhostwebsite.com/tc.html?ah=true"

Siemens PLM Software - Confidential Page 10


Active Workspace Hosting Programmers Guide – V2.4

3. Existing Hosting Services


Currently, services are separated into two different levels:

 Infrastructure - lower level services, handling communication and other basic API ‘plumbing’.
 Solutions - more application-level functionality.

Further, all services have both a name and a version. It's possible for there to be multiple versions with
the same service name, performing similar tasks.

In the listings below, the specific services are shown as (name/version).

Note: A brief description of the currently available host-side and client-side services can be displayed
by the Active Workspace server by navigating with your browser to the following relative address:

http://<aw_server>/thinclient/lib/host_integration/hostServices.html

Siemens PLM Software - Confidential Page 11


Active Workspace Hosting Programmers Guide – V2.4

Host-Side Services
The following sections provide a brief description of the existing services a host can choose to provide
implementations for. The implementations will process client-side requests to these services. All of
these services are optional.

SOA Related ‘Infrastructure’ Services


These services provide support for SOA tunneling, which allows the hosted client application to share
the SOA connection and credentials of the host application.

Async Soa JSON Message


FQN: splm.browserinterop.infrastructure.services.soa.AsyncSoaJsonMessage.host / _2014_02

This service is called by the client to have the host perform an SOA operation.

Host Session Info


FQN: splm.browserinterop.infrastructure.services.soa.HostSessionInfo.host / _2014_02

This service is called when the client needs information about the current SOA session.

Request Host Authorization


FQN: splm.browserinterop.infrastructure.services.soa.RequestHostAuth.host / _2014_02

This service is called when the client wishes to asynchronously start a session for the given user.

General ‘Infrastructure’ Services

Client Status
FQN: splm.browserinterop.infrastructure.services.core.ClientStatus.host / _2014_07

This service is called by the client to announce changes in its state.

Logger Forwarder
FQN: splm.browserinterop.infrastructure.services.LoggerForward.host / _2014_02

This service is called when the client wants the host to log some 'routine' message.

Refresh
FQN: splm.browserinterop.infrastructure.services.refresh.Refresh.host / _2014_07

This service is called by the client to have the host perform a refresh of its data model based on the
object references it supplies.

Session
FQN: splm.browserinterop.infrastructure.services.session.Session.host / _2014_07

This service is called by the client to have the host react to various types of session changes.

Siemens PLM Software - Confidential Page 12


Active Workspace Hosting Programmers Guide – V2.4

Host Configuration
FQN: splm.browserinterop.infrastructure.services.core.HostConfiguration.host / 2014_02 & 2014_07

This service is called by the client to get the host's configuration for it.

General ‘Solutions’ Services

Host Open
FQN: splm.browserinterop.solutions.services.open.HostOpen.host / _2014_02

This service is called when the client wants the host to open one or more components in some host
appropriate view(s).

Remote Clipboard
FQN splm.browserinterop.services.clipboard.RemoteClipboard.host / _2014_07

This service is called by the client to have the host add or remove items from its clipboard.

Selection Provider
FQN: splm.browserinterop.solutions.services.selection.SelectionProvider.host / _2014_02

This service is called when the client wishes to have one or more objects selected in the host
application.

Siemens PLM Software - Confidential Page 13


Active Workspace Hosting Programmers Guide – V2.4

Client-Side Services
The following sections provide a brief description of the existing services a client can choose to provide
implementation for. The implementations will process host-side requests to these services. All of these
services are optional.

SOA Related ‘Infrastructure’ Services

Request Host Authorization Reply


FQN: splm.browserinterop.infrastructure.services.soa.RequestHostAuthReply.client / _2014_02

This service is called by the host to complete the client's asynchronous request for user session
authorization.

JSON Request
FQN: splm.browserinterop.infrastructure.services.soa.SoaJsonRequest.client / _2014_02

This service is called by the host to return data from an asynchronous SOA call.

Request Host Authorization Reply


FQN: splm.browserinterop.infrastructure.services.soa.RequestHostAuthReply.client / _2014_02

This service is called by the host to complete the client's asynchronous request for user session
authorization.

General ‘Infrastructure’ Services

Open Location
FQN: splm.browserinterop.infrastructure.services.openlocation.OpenLocation.client / _2014_02

This service is called by the host to have the client go to a specific location within the hosted
application.

Refresh
FQN: splm.browserinterop.infrastructure.services.refresh.Refresh.client / _2014_07

This service is called by the host to have the client perform a refresh of its data model based on the
object references it supplies.

Session
FQN: splm.browserinterop.infrastructure.services.session.Session.client / _2014_07

This service is called by the host to have the client react to various types of session changes.

General ‘Solutions’ Services

Component Config
FQN splm.browserinterop.services.component.ComponentConfig.client / _2014_07

Siemens PLM Software - Confidential Page 14


Active Workspace Hosting Programmers Guide – V2.4

This service is called by the host to set the component configuration

Get Available Themes


FQN: splm.browserinterop.solutions.services.theme.GetAvailableThemes.client / _2014_02

This service is called by the host to get the names of currently available styling themes.

Get File Ticket


FQN: splm.browserinterop.solutions.services.fileticket.GetTicket.client

This service is called by the host to have the client generate a URL to upload/download a file.

Initiate Search
FQN: splm.browserinterop.solutions.services.search.InitiateSearch.client / _2014_02

This service is called by the host to have the client perform a search with the given string and to
display the results.

Object Info Component Input


FQN: splm.browserinterop.services.component.ObjectInfoComponentInput.client / _2014_07

This service is called by the host to set input for the object info component

Remote Clipboard
FQN: splm.browserinterop.services.clipboard.RemoteClipboard.client / 2014_07

This service is called by the host to have the client add or remove items from its clipboard

Selection Listener
FQN: splm.browserinterop.solutions.services.selection.SelectionListener.client / 2014_02

This service is called by the host to pass objects to the client to be selected.

Set Theme
FQN: splm.browserinterop.solutions.services.theme.SetTheme.client / _2014_02

This service is called by the host to set the current styling theme.

Siemens PLM Software - Confidential Page 15


Active Workspace Hosting Programmers Guide – V2.4

4. Invoking Proxies
A proxy is the host-side object used to invoke a client-side service. If you want to invoke proxies from
the host application, you must create an instance of that proxy, and then call methods on it.

For example, let's call the HelloWorldProxy explained later in this document.

Java
HelloWorldProxy proxy = new HelloWorldProxy( webHostControl.getHostInstanceData() );
proxy.SendHelloWorld();

C++
HelloWorldProxy proxy( hostControlInstance );
proxy.SendHelloWorld();

JavaScript
var proxy = new HelloWorldProxy( hostControl );
proxy.SendHelloWorld();

Siemens PLM Software - Confidential Page 16


Active Workspace Hosting Programmers Guide – V2.4

5. How to Write a Proxy


Here's a simple “Hello World” example of writing a proxy. First we will define the proxy. Our proxy is
named HelloWorldProxy and it sends a message across to the service implementation to be displayed.

The high-level steps to write a proxy are:

1) Create a class and subclasses that extend BaseServiceProxy


2) Define a constructor that registers the HostControlInstance with the proxy name.
3) Define a SendHelloWorld proxy method that will be invoked from the host.
4) Define the HelloWorldMessage that is the payload passing back and forth between the Host
and Proxy service.

The detailed steps to do this are:

1) Define the HelloWorldProxy class that extends the BaseServiceProxy class.


2) Define the constructor, which takes in the associated HostControlInstance, and passes the
name of the service com.sample.HelloWorld.client, and the version _2014_07 to the
constructor of the base class, BaseServiceProxy.
3) Define the SendHelloWorld function to call the service
4) Create an instance of the HelloWorldMessage and pass in the message we want to send
"Hello World".
5) Convert the message object into a JSON formatted string to be sent to the service.
6) Use the HostControlInstance object (passed in earlier) to invoke the client-side service,
passing in the message.

Here are language-specific examples of the steps:

Siemens PLM Software - Confidential Page 17


Active Workspace Hosting Programmers Guide – V2.4

Java
package com.siemens.splm.browserinterop.solutions.services.helloWorld._2014_07;

import com.google.gson.Gson;
import com.siemens.splm.browserinterop.infrastructure.interop.IHostControlInstance;
import com.siemens.splm.browserinterop.infrastructure.services.BaseServiceProxy;

// Step 1
public class HelloWorldProxy
extends BaseServiceProxy
{
// Step 2
public HelloWorldProxy( IHostControlInstance hostcontrol )
{
super( hostcontrol, "com.sample.HelloWorld.client", "_2014_07" );
}

// Step 3
public void SendHelloWorld() throws Exception
{
// Step 4
HelloWorldMessage msg = new HelloWorldMessage( "Hello World", "_2014_07" );
// Step 5
String payload = new Gson().toJson( msg );
try
{
if( _hostControl != null )
{
// Step 6
_hostControl.invokeWebEvent( getTargetServiceDescriptor(), payload );
}
}
catch( Exception ex )
{
// some error invoking the service - likely not able to communicate with client-side.
BaseServiceProxy.logError( "Cannot call client-side for method invocation: "
+ ex.getLocalizedMessage(), ex );
throw ex;
}
}
}

C++
#include <infrastructure/services/BaseServiceProxy.hxx>
#include <infrastructure/interop/HostlibExports.hxx>
#include <infrastructure/interop/IHostControlInstance.hxx>
namespace Com { namespace Siemens { namespace SPLM { namespace BrowserInterop { namespace Solutions { namespace Services
{ namespace HelloWorld { namespace _2014_07 {
/* Step 1 */
class HelloWorldProxy : public BROWSERINTEROP_SERVICES_NS::BaseServiceProxy
{
public:
/* Step 2 */
HelloWorldProxy(BROWSERINTEROP_INTEROP_NS::IHostControlInstance* hostControl)
: BROWSERINTEROP_SERVICES_NS::BaseServiceProxy(hostControl, "com.sample.HelloWorld.client", "_2014_07")
{
}
void SendHelloWorld()
{
/* Step 4 */
HelloWorldMessage msg("Hello World", "_2014_07");

Siemens PLM Software - Confidential Page 18


Active Workspace Hosting Programmers Guide – V2.4

/* Step 5 */
std::string payload = msg.ToJsonString();
if( m_hostControl != NULL )
{
/* Step 6 */
m_hostControl->InvokeWebEvent(GetBaseServiceDescriptor(), payload);
}
}
}; } } } } } } } }

JavaScript
// Step 1
var HelloWorldProxy = function (hostControl) {
// Step 2
INF_SERVICES.BaseServiceProxy.call(this, hostControl,
“com.sample.HelloWorld.client”, “_2014_07”);
};

HelloWorldProxy.prototype = Object.create(INF_SERVICES.BaseServiceProxy.prototype);

// Step 3
HelloWorldProxy.prototype.SendHelloWorld = function(){
// Step 4
var msg = new HelloWorldMessage( "Hello World", "_2014_07" );
// Step 5
String payload = JSON.stringify( msg );
try{
if(this.hostControl){
// Step 6
this.hostControl.invokeWebEvent( this.getTargetServiceDescriptor(), payload );
}
}catch(ex){
// some error invoking the service - likely not able to communicate with client-side.
Console.log ( "Cannot call client-side for method invocation: " + ex );
throw ex;
}
}

Proxy Messages
Now let's take a look at the HelloWorldMessage class. Message classes are used to hold the
information that's being passed across the inter-process boundary to the service on the other side.

Siemens PLM Software - Confidential Page 19


Active Workspace Hosting Programmers Guide – V2.4

Java
package com.siemens.splm.browserinterop.solutions.services.helloWorld._2014_07;

import com.siemens.splm.browserinterop.infrastructure.services.BaseDataContractImpl;

public class HelloWorldMessage


extends BaseDataContractImpl
{
public String Message;

protected HelloWorldMessage( String message, String version )


{
super( version );
Message = message;
}
}

C++
#include <infrastructure/interop/HostlibExports.hxx>
#include <infrastructure/services/BaseMessage.hxx>

namespace Com { namespace Siemens { namespace SPLM { namespace BrowserInterop { namespace Solutions { namespace Services
{ namespace HelloWorld { namespace _2014_07 {

class HelloWorldMessage : public BROWSERINTEROP_SERVICES_NS::BaseMessage


{
public:
HelloWorldMessage(const std::string& message, const std::string& version) :
BROWSERINTEROP_SERVICES_NS::BaseMessage(version), Message(message)
{
RegisterField("Message", Message);
}
std::string Message;
}; } } } } } } } }
Note: In C++ it is necessary to call RegisterField for each field in the message. This ensures that the
value is passed across the inter-process communication boundary. The first parameter is the name of
the field. The other side of the communication boundary must use this same name to reference the
field. The second parameter is a reference to the value for the field.

JavaScript
var HelloWorldMessage = function ( message, version ) {
INF_SERVICES.BaseDataContractImpl.call(this, version);
this.FormatMessage = message;
};

HelloWorldMessage.prototype = Object.create(INF_SERVICES.BaseDataContractImpl.prototype);

HelloWorldMessage.prototype.getMessage = function(){
return this.FormatMessage;
}

Siemens PLM Software - Confidential Page 20


Active Workspace Hosting Programmers Guide – V2.4

6. How to Write a Service


Now that we've defined the proxy, let's define the service that it will be calling into. Services essentially
do the heavy lifting, while the proxy is a pass-through to the service on the other side of the inter-
process communication boundary.

The detailed steps to do this are:

1) Within the service's constructor, we'll pass the name of the service
“com.sample.HelloWorld.client”, and the version “_2014_07” to the base class
BaseCallableService. If the name and version numbers don't match the ones used in the
proxy, the host manager will be unable to find the service called by the proxy, and the proxy will
fail.
2) Override the handleIncomingEvent function to handle the call from the proxy.
3) Change the simple text of the JSON message into a class.
4) Call into the call to get the message that was sent to us from the proxy.
5) Print out the message. In this case, "Hello World!" is seen.

Siemens PLM Software - Confidential Page 21


Active Workspace Hosting Programmers Guide – V2.4

Java
package com.siemens.splm.client.hosted.services.helloworld._2014_07;
import com.siemens.splm.clientfx.bootstrap.hosted.published.services.BaseCallableService;
public class HelloWorldSvc
extends BaseCallableService
{
/**
* Constructor
*/
public HelloWorldSvc()
{
// Step 1
super( "com.sample.HelloWorld.client", "_2014_07" );
}

// Step 2
@Override
public void handleIncomingEvent( String jsondata )
throws Exception
{
String message = null;

// Step 3
HelloWorldMsg msg = HelloWorldMsg.getResponseFromJson( jsondata );
if( msg != null )
{
// Step 4
message = msg.getMessage();
}

// Step 5
System.out.println( message );
}
}

JavaScript
// Step 1
var HelloWorldSvc = function() {
INF_SERVICES.BaseHostingService.call(this, "com.sample.HelloWorld.client", "_2014_07" );
};

HelloWorldSvc.prototype = Object.create(INF_SERVICES.BaseHostingService.prototype);

// Step 2
HelloWorldSvc.prototype.handleIncomingEvent = function( jsondata ){
var message = null;
// Step 3
var msg = JSON.parse(jsondata);
if( msg ){
// Step 4
message = msg.getMessage();
}

// Step 5
Console.log( message );
};

Siemens PLM Software - Confidential Page 22


Active Workspace Hosting Programmers Guide – V2.4

7. Hosting a Component
Components are functional pieces of Active Workspace that can be hosted as a stand-alone application.
Typically, a component will either allow a user to perform a task or show information to the user.

Components are hosted in the same way as the full Active Workspace client. They can utilize common
services for soa, authentication, session, etc. While a component is only a small piece of Active
Workspace from a programming perspective it is the same as the full client and requires its own
HostControlInstance and its own authentication. This means a hosted component cannot share them
with another hosted instance of Active Workspace.

When hosting a component the URL used is the standard Active Workspace URL with component
location appended by adding
#com.siemens.splm.clientfx.ui.components.ComponentsPresenter to the end of the URL.
Every component in Active Workspace is identified with a unique string identifier; to host a particular
component it is necessary to know its identifier. The component identifier can be set either by adding it
to the URL with the parameter componentId or by setting it through the
ComponentConfigurationProxy described in Service Details.

A component can both accept input and send output. Input can be sent either through aparameter in
the URL or by invoking a proxy in the host-side code. Output can be received by implementing a service
on the host-side code that will be called by the client component. Input proxies and output services are
specific to a particular component. An example of an input proxy is shown in the ObjectInfo
Component Input section under Service Details.

Component Example URLs


http://<host>:<port>/awc/tc.html#com.siemens.splm.clientfx.ui.components.ComponentsPresenter
Access the component location but don't load any component
http://<host>:<port>/awc/tc.html?componentId=<id>#com.siemens.splm.clientfx.ui.components.ComponentsPresenter
Access the component location with a specific component loaded
http://<host>:<port>/awc/tc.html?componentId=<id>&<parameter1>=<value>#com.siemens.splm.clientfx.ui.components.ComponentsPre
senter
Access the component location with a specific component loaded and passes a parameter to the
component.
http://<host>:<port>/awc/tc.html?embeddedLocationView=true#com.siemens.splm.clientfx.tcui.xrt.showObject;uid=<value>
Access the showObject location, use the embedded location view, and show a particular object
specified by uid

Service Details

Client Info
For logging purposes it may be useful for the host to know information about the Active Workspace
client it is connected to. The ClientInfoProxy provides a way for the host to query this information.

Siemens PLM Software - Confidential Page 23


Active Workspace Hosting Programmers Guide – V2.4

It can be called by the host any time after communication has been established between host and client.
The return value is a list of key / value string pairs. Currently Active Workspace provides information
about its version and URL.

Current key values that can be returned:

clientVersionNumber - Active Workspace client version ex. 2.2

clientBuildLabel - Active Workspace client build version ex. 20140820

clientUrl - Current URL of the Active Workspace client

Example code

C++
BROWSERINTEROP_SERVICES_NS::ClientInfo::_2014_07::ClientInfoProxy clientInfoProxy(GetHostControlInstance()-
>GetHostControlInstance());

std::map<std::string,std::string> info = clientInfoProxy.GetClientInfo();

std::map<std::string,std::string>::const_iterator findResult = info.find("clientVersionNumber");


if (findResult != info.end())
{
const std::string& versionNumber = findResult->second;
printf("Loaded Active Workspace Client version: %s\n", versionNumber.c_str());
}

Component Configuration
The component configuration sets up the configuration of the component system; it does not set
options specific to a component. Currently, the following fields are available in ComponentConfigMsg:

C++
class HOSTLIBEXPORT ComponentConfigMsg : public BROWSERINTEROP_SERVICES_NS::BaseMessage
{
public:
ComponentConfigMsg();
/// <summary>
/// Component id.
/// </summary>
std::string ComponentId;
/// <summary>
/// Should the client display in the embedded location view?
/// </summary>
bool UseEmbeddedLocationView;
};
The component configuration can be set by using the ComponentConfigProxy:

Siemens PLM Software - Confidential Page 24


Active Workspace Hosting Programmers Guide – V2.4

C++
class HOSTLIBEXPORT ComponentConfigProxy : public BROWSERINTEROP_SERVICES_NS::BaseServiceProxy
{
public:
/// <summary>
/// ctor - associate this with a particular web container.
/// </summary>
/// <param name="hostcontrol">the host control instance.</param>
ComponentConfigProxy(BROWSERINTEROP_INTEROP_NS::IHostControlInstance* hostControl);

~ComponentConfigProxy();

void SetComponentConfiguration(const ComponentConfigMsg& config);


};
Currently, the following fields are available:

ComponentId – The id of the component.

UseEmbeddedLocationView – Should the page be displayed using the embedded location view? For
example, should the header, footer, command bars, search box, etc. be hidden? This affects all pages
and does not require ComponentId to be set in order to take effect.

ObjectInfo Component Input

To use the ObjectInfo component it is necessary to first invoke the ComponentConfigProxy and set
the ComponentId field in the ComponentConfigMsg to
com.siemens.splm.clientfx.tcui.xrt.published.ObjectInfo

The ObjectInfoPresenterW component allows the object to render to be set.

C++
class HOSTLIBEXPORT ObjectInfoComponentInputMsg : public BROWSERINTEROP_SERVICES_NS::BaseMessage
{
public:
ObjectInfoComponentInputMsg();
/// <summary>
/// Object to display.
/// </summary>
BROWSERINTEROP_SERVICES_NS::Core::_2014_02::InteropObjRef ObjectRef;
};
Currently, the following fields are available:

ObjectRef - the object the component should render.

The object that the ObjectInfo component is rendering can be updated by using the
ObjectInfoComponentInputProxy and calling UpdateObject

Siemens PLM Software - Confidential Page 25


Active Workspace Hosting Programmers Guide – V2.4

C++
class HOSTLIBEXPORT ObjectInfoComponentInputProxy : public BROWSERINTEROP_SERVICES_NS::BaseServiceProxy
{
public:
/// <summary>
/// ctor - associate this with a particular web container.
/// </summary>
/// <param name="hostcontrol">the host control instance.</param>
ObjectInfoComponentInputProxy(BROWSERINTEROP_INTEROP_NS::IHostControlInstance* hostControl);

~ObjectInfoComponentInputProxy();

void UpdateObject(const BROWSERINTEROP_SERVICES_NS::Core::_2014_02::InteropObjRef& object);


};

Refresh
When hosting AW, both the host and AW have independent local data models. If AW triggers a change
to a model object, the change may need to be reflected in the host's client-side data model. Likewise, if
the host triggers a change to a model object, the change may need to be reflected in the AW client-side
data model. Without a mechanism to synchronize the two client-side data models, both the host and
AW may be presenting different information about the same loaded object. For example, the host may
show an object as checked out and AW may show it as checked in.

To provide the necessary client-side data synchronization between the host and AW, we can use a
client-side BIO service (Refresh) to send across the relevant object modifications. When the host makes
a change to an object loaded in its client-side data model, it will send the affected list of objects to AW.
The list of impacted objects can be created in the host from information returned in the response to the
SOA call modifying the objects. SOA provides a list of added, removed, and updated objects for each
SOA call (a.k.a. service data). This list of objects is sent to AW, and AW uses it to refresh its client-side
data model accordingly. Since AW also uses SOA, this mechanism becomes bi-directional. If AW modifies
an object, the corresponding SOA call's service data can be used to update the host.

For the host to communicate object-level modifications to AW, it needs to use the Refresh service.
Specifically, it must invoke RefreshProxy::sendRefresh and pass along the object UIDs
representing the created, updated, and deleted objects. AW will use this list to update its client-side
data model and refresh the UI if required.

For the host to receive object level modifications from AW, it needs to register the RefreshSvc and
implement a handler (IRefreshHandler). When AW makes a server call resulting in a created,
updated, or deleted object, it will pass this information to the host within a RefreshMsg. The
RefreshMsg contains a list of created, updated, and deleted objects. It is up to the host to decide what
to do, if anything, after it receives this information. In general, however, the host will trigger an SOA call
to refresh these objects so that they are updated and/or loaded within its client-side data model.

Below is the handler that is invoked in the host after AW makes changes to a set of objects.

Siemens PLM Software - Confidential Page 26


Active Workspace Hosting Programmers Guide – V2.4

Java
/**
* Interface implemented on the host-side tasked with handling client data model updates initiated from the client-side.
*/
public interface IRefreshHandler
{
/**
* Update the host-side client data model based on the given object references.
*
* @param createdObjects List of {@link InteropObjectRef} to objects that have been created.
* @param deletedObjects List of {@link InteropObjectRef} to objects that have been deleted.
* @param updatedObjects List of {@link InteropObjectRef} to objects that have been updated.
*/
void refreshHost( List<InteropObjectRef> createdObjects, List<InteropObjectRef> deletedObjects,
List<InteropObjectRef> updatedObjects );
}

Session
Similar to how model object changes can be synchronized using the Refresh service; session level
changes can be synchronized using the Session service. Session level objects such as GroupMember,
RevisionRule, Project, and Preferences (future) can all be synchronized using the Session
service.

For the host to communicate session changes to AW, it needs to use the Session service. The
SessionProxy::updateSession method should be invoked, passing along the changed session
objects (GroupMember, RevisionRule, default Project). The API has a placeholder for preferences
which are currently not implemented. When AW receives the list of changed session objects, it will
update its internal session settings and update the UI, if required.

For the host to receive session level changes from AW, it needs to register the SessionSvc and
implement a handler (ISessionHandler). AW will trigger this handler after session changes have been
made within AW (currently only RevisionRule is supported). It is up to the host to decide what to do, if
anything, after receiving the session information.

Below is the host-side handler that is invoked after AW makes a session change.

Java
/**
* Interface implemented on the host-side tasked with handling session updates initiated from the client-side.
*/
public interface ISessionHandler
{
/**
* Update the host-side session based on the given object references.
*
* @param sessionObjects List of {@link InteropObjectRef} to session objects that have been updated
* (group member, rev rule, project).
*
* @param properties List of {@link StringArrayProperty} to preferences (name/value pairs)
* that have been updated.
*/
void handleSessionRequest( List<InteropObjectRef> sessionObjects, List<StringArrayProperty> properties );
}

Siemens PLM Software - Confidential Page 27


Active Workspace Hosting Programmers Guide – V2.4

8. Handshake Phase State Diagram


The initial communication between the host and client applications is critical to the dependable and
secure use of the hosting APIs. This initial communication is referred to as the 'handshake' phase. This
phase supports the necessary asynchronous nature of host-client communication. Like all host-client
communication, it is controlled by the HostControlInstance (HCI).

A simplified overview of the 'handshake' phase steps after basic host-side initialization is:

1) HCI tells a web browser to load a URL that specifies the client-side to be hosted.
2) HCI waits till client invokes webSideStartHandShake method in the HCI.
3) HCI 'Pings' the client to assure bi-directional communications are working.
4) HCI pushes the list of supported host-side services to the client.
5) HCI requests the client to return a list of its supported client-side services.
6) HCI invokes the StartupNotification.client service on the client. The client is now
responsible for completing any login/authorization.
7) HCI waits till the client invokes the StartupNotification.host service on the host.

At this point, the 'handshake' phase is largely complete and normal bi-directional communication can
now continue. The next step is optional, but common, and allows the host to configure some specific
options in the client's UI and its operation:

Client invokes HostConfigurationSvc.host which returns a set of name/value pairs. These define
the host's desired options for the client to honor.

For a more complete state diagram of these 'handshake' phase steps (and some other common host-
client iterations), follow this link:

BIO_2.2.3.20140926_HandShakeStates_Full.png

Siemens PLM Software - Confidential Page 28


Active Workspace Hosting Programmers Guide – V2.4

The diagram is rather large, but a basic thumbnail overview is:

Siemens PLM Software - Confidential Page 29


Active Workspace Hosting Programmers Guide – V2.4

9. Active Workspace URLs


The following are examples of the URLs that can be used to access Active Workspace in different ways.
You would need to replace 111.222.333.444 with the name of the server hosting your Active Workspace
installation and 7001 with the port your Active Workspace web server is running on.
http://111.222.333.444/awc/tc.html
Access the standalone Active Workspace client
http://111.222.333.444:7001/awc/tc.html?ah=true
Access the hosted version of the Active Workspace client
http://111.222.333.444:7001/awc/tc.html?#com.siemens.splm.clientfx.tcui.xrt.showObject;uid=RtKdVScox6sBFD
Access the standalone Active Workspace client and display the summary page for the object with the
UID RtKdVScox6sBF
http://111.222.333.444:7001/awc/tc.html?embeddedLocationView=true#com.siemens.splm.clientfx.tcui.xrt.showObject;uid=RtKdVSco
x6sBFD
Access the standalone Active Workspace client and display the summary page for the object with the
UID RtKdVScox6sBFD and show only the summary information with no titles, command bars, etc.
http://111.222.333.444:7001/awc/tc.html?componentId=com.siemens.splm.clientfx.tcui.xrt.published.ObjectInfo&uid=iuTJp5uxx6sB
FD#com.siemens.splm.clientfx.ui.components.ComponentsPresenter
Access the ObjectInfo component for the object with the UID iuTJp5uxx6sBFD. This will show the
Info panel for the object in full screen mode.

Siemens PLM Software - Confidential Page 30


Active Workspace Hosting Programmers Guide – V2.4

10. Global Methods in Browser


Both the host and client are responsible for adding certain methods into the global space of the browser.
These methods facilitate the communication between the two.

Siemens PLM Software - Confidential Page 31


Active Workspace Hosting Programmers Guide – V2.4

11. Trouble Shooting


I'm having trouble connecting
1) First, verify that the URI being used is valid. Attempt to load it in a standard browser, and make
sure the client functions normally.
2) Verify that you have registered the services you're attempting to use.
3) If you're using SOA, make sure that the HostSessionInfoHandler's obtainSessionInfo is
getting called.

I'm having trouble with a service


1) Verify that the service name and version match on both the client and host.
2) Verify that both the service and proxy are both using either invokeEvent or invokeMethod.

I'm still having trouble


1) Load the BIO library source.
2) If you having trouble with the initial communication try putting break points in the
HostControlInstance::websideStartHandShake which should be called by the client
when it starts communication. Also add a break point in
HostControlInstance::webSideServiceListUpdate and make sure that the client is
passing in a list of available services.
3) If you having trouble with services, try putting breakpoints in CallBackFunctions for
IC_SplmHostMethodFunction and IC_SplmHostEventFunction.

Siemens PLM Software - Confidential Page 32


Active Workspace Hosting Programmers Guide – V2.4

12. Example #1 - Javascript - "Hello Hosting"


The following example code demonstrates the minimum Javascript code required to host the Active
Workspace client within an <iframe> of a web page. The only host-side service provided is
LoggerForwardSvc. This implementation just lists message information from the client to the
browser’s console.

Note: This example assumes you have deployed the Active Workspace client and this example code
at: http://localhost:8080/. If this is not true you will need to update the URL in the
index.html file.

Deployment Structure
Deploy the example files to your web server using the following structure.
<webserver root>/
tests/
index.html
js/
helloHosting.js
splmBrowserInterOp.js (from hosting deployment)
Once this is done, you can run the test by loading the following URL:

http://<webserver>/tests/index.html

Html (tests/index.html)
<!DOCTYPE html>
<html>

<head>
<title>Hello Hosting</title>
<script type="text/javascript" src="js/splmBrowserInterOp.js"></script>
<script type="text/javascript" src="js/helloHosting.js"></script>
</head>

<body onload="HELLO_HOSTING.initializeHosting('http://localhost:8080/?ah=true')">
<iframe src="" width="100%" height="100%" id="clientIFrame"></iframe>
</body>

</html>

Siemens PLM Software - Confidential Page 33


Active Workspace Hosting Programmers Guide – V2.4

Javascript (tests/js/helloHosting.js)
/*global
INF_INTEROP,
INF_SERVICES_LOGGING_2014_02,
INF_UTILS,
window
*/

/**
* The Classes and Methods in this namespace implement a simple 'hello world' example of hosting a client.
* <P>
* It provides an example of:
* <ul>
* <li>Define a local handler for the LoggerForwardSvc that extends the ILogEntryHandler interface class.</li>
* <li>Locate the <iframe> (defined in the index.html) that AW client will be hosted within.</li>
* <li>Get the INF_INTEROP.HostManager singlton.</li>
* <li>Register the local handler for the LoggerForwardSvc with the INF_INTEROP.HostManager</li>
* <li>Set the URL to the Active Workspace client provided to the 'HELLO_HOSTING.initializeHosting' method</li>
* </ul>
* When the URL is set into the <iframe>, the Active Workspace client will be launched and the 'handshake' phase between
* this host and that client will performed. After this, all logging events generated in client will be sent to the
* host-side logging service and logged by the MyLogEntryHandler class.
*
* @namespace HELLO_HOSTING
* @ApiVisibility( maturity = MaturityEnum.Experimental, publishScope = Scope.Public )
*/
(function (HELLO_HOSTING) {

/**
* Implements (extends) the {@link INF_SERVICES_LOGGING_2014_02.ILogEntryHandler|ILogEntryHandler} interface.
*
* @constructor MyLogEntryHandler
*
* @augments INF_SERVICES_LOGGING_2014_02.ILogEntryHandler
*/
function MyLogEntryHandler () {
INF_SERVICES_LOGGING_2014_02.ILogEntryHandler.call(this);
}

MyLogEntryHandler.prototype = Object.create(INF_SERVICES_LOGGING_2014_02.ILogEntryHandler.prototype);

/**
* Simply lists out the properties of the arriving log entry message.
*
* @see {@link INF_SERVICES_LOGGING_2014_02.ILogEntryHandler}
*/
MyLogEntryHandler.prototype.handleEntry = function (msg) {
INF_UTILS.logMessage( //
"vvvvv [From client-side logging:]\n" + //
"Version: " + msg.getVersion() + " " + //
"Level: " + msg.getLevel() + "\n" + //
msg.getFormatMessage() + "\n" + //
"^^^^^");
};

/**
* This callback method is invoked by the INF_INTEROP.HostManager as part of the initialization of the
* INF_INTEROP.HostControlInstance. Any services and their handlers provided this host should be registered here.
*
* @param {INF_INTEROP.HostManager}

Siemens PLM Software - Confidential Page 34


Active Workspace Hosting Programmers Guide – V2.4

* hostManager - Object to register the host-side services with.


*/
function registerHostServices (hostManager) {
var loggerForwardService = new INF_SERVICES_LOGGING_2014_02.LoggerForwardSvc(new MyLogEntryHandler());
hostManager.registerService(loggerForwardService);
}

/**
* Initialize INF_INTEROP.HostManager with the required host-side services and create the
* INF_INTEROP.HostControlInstance used for all future interaction between the host and client.
*
* @param {String}
* url - URL to the Active Workspace client (assumed to have the ah=true query already added to it).
*/
HELLO_HOSTING.initializeHosting = function (url) {
var clientIFrame = document.getElementById("clientIFrame");

var hostManager = INF_INTEROP.getHostManagerInstance();

if (hostManager) {
hostManager.initializeHostIntegration(clientIFrame, registerHostServices);
}

clientIFrame.src = url;
};

}(window.HELLO_HOSTING = window.HELLO_HOSTING || {}));

Siemens PLM Software - Confidential Page 35


Siemens Industry Software

Headquarters
Europe
Granite Park One
Stephenson House
5800 Granite Parkway
Sir William Siemens Square
Suite 600
Frimley, Camberley
Plano, TX 75024
Surrey, GU16 8QD
USA
+44 (0) 1276 413200
+1 972 987 3000

Asia-Pacific
Americas
Suites 4301-4302, 43/F
Granite Park One
AIA Kowloon Tower, Landmark East
5800 Granite Parkway
100 How Ming Street
Suite 600
Kwun Tong, Kowloon
Plano, TX 75024
Hong Kong
USA
+852 2230 3308
+1 314 264 8499

About Siemens PLM Software

© 2015 Siemens Product Lifecycle Management


Siemens PLM Software, a business unit of the Siemens
Software Inc. Siemens and the Siemens logo are
Industry Automation Division, is a leading global provider
registered trademarks of Siemens AG. D-Cubed,
of product lifecycle management (PLM) software and
Femap, Geolus, GO PLM, I-deas, Insight, JT, NX,
services with 7 million licensed seats and 71,000 customers
Parasolid, Solid Edge, Teamcenter, Tecnomatix and
worldwide. Headquartered in Plano, Texas, Siemens
Velocity Series are trademarks or registered trademarks
PLM Software works collaboratively with companies
of Siemens Product Lifecycle Management Software
to deliver open solutions that help them turn more
Inc. or its subsidiaries in the United States and in other
ideas into successful products. For more information
countries. All other trademarks, registered trademarks
on Siemens PLM Software products and services, visit
or service marks belong to their respective holders.
www.siemens.com/plm.

You might also like