tvc.collaboration.appServerNotificationStrategy = ehcache | http
21 March 2016
© Copyright 2003-2016 by TechniaTranscat AB
All rights reserved.
PROPRIETARY RIGHTS NOTICE: This documentation is proprietary property of TechniaTranscat AB. In accordance with the terms and conditions of the Software License Agreement between the Customer and TechniaTranscat AB, the Customer is allowed to print as many copies as necessary of documentation copyrighted by TechniaTranscat relating to the software being used. This documentation shall be treated as confidential information and should be used only by employees or contractors with the Customer in accordance with the Agreement.
This product includes software developed by the Apache Software Foundation. (http://www.apache.org/).
The TVC Core is the base component for all the components within the TVC suite. TVC Core provides a framework with a large number of features and services that are used by the TVC components. There are also some parts in TVC core that can be used stand-alone, without the presence of any other TVC component. This document describes those features.
The Developer Documentation contains additional information such as descriptions on how to use the TVC Core framework (MVC, Ajax, TVC plugins etc) and how to use classes from TVC Core. This document will focus on the features that are configurable.
The TVC Collaboration feature adds a set of functionality that allows users to collaborate around ENOVIA™ data in various ways. Some of the features are:
Discussions in context of ENOVIA™ objects
Real time notifications on discussion events
Inbox to view received notifications
Profile page with settings and ability to upload an avatar
The following is a list of the requirements for the installation of this TVC. If your system is different, consult Technia before installing. For best performance it is recommended to use the latest version of browsers and application servers.
Supported ENOVIA™ versions
V6R2013
V6R2013X
V6R2014
V6R2014X
V6R2015X
Supported Browsers
Internet Explorer 10 and 11
Mozilla Firefox (current and prior major release)
Chrome (current and prior major release)
Application Server according to the ENOVIA™ core product requirements that is also in the list of supported platforms for the Atmosphere framework (see disclaimer below).
If you are using multiple application servers, you must read the next chapter.
For the Exalead™ powered features you need to install and setup Exalead
Disclaimer: This feature uses a framework called Atmosphere for sending notifications from the server to the clients. This framework supports a wide range of browser and app servers. We will not be able to add support for browsers and/or app servers that is outside of this frameworks support. Also we might not be able to fix issues that could appear in the usage of this framework. See following pages for a list of this frameworks supported platforms and known issues:
Many environments are scaled horizontally to support a larger amount of users. When having > 1 application server you need to use a load balancer that can divide the users across these application servers somehow.
The Collaboration component uses the web socket technology for setting up persistent connections between clients and servers and this technology has a completely different analogy than the traditional request/response paradigm used in HTTP/HTTPS communication. This will have some impact on your infrastructure since your load-balancer must be able to deal with web sockets correctly.
| Technia cannot support every possible infrastructure combination. We can however share information how we have tested it, on what software’s and our configurations. To enable this feature in your own environment / setup-combination you must consult the documentation of your infrastructure components. |
Since users in fact are connected to different application servers, but still should be able to receive notifications from other users – there is a need for the application servers to be able to speak with each other.
There are currently two different implementations available that solves this, one of the implementation uses HTTP communication between the servers and the second implementation uses the Open Source library named Ehcache. The latter is the default communication strategy.
The choice of strategy is defined with a TVC init-parameter. The name of the parameter and the possible values are shown below:
tvc.collaboration.appServerNotificationStrategy = ehcache | http
The Ehcache™ component allows us to setup caches which are replicated among all the other application servers in the same cluster. This replication is done via the RMI protocol and each application server in the cluster is joining a TCP multicast-group.
The strategy of this implementation will try to automatically setup the network communication, but, there are some init-parameters that you may want to fine-tune for some reason or other.
For example, the port that we bind to is automatically picked by selecting a random free port within a specified range. Most likely, you want to define the port manually and in some cases also the network interface to bind to. If your host has multiple network interfaces you might need to specify the host name also. By default, the host name is resolved via the Java API:
InetAddress.getLocalHost().getHostAddress()
Defining the port and host can be done either with JVM system parameters OR TVC init parameters. The parameter name is the same regardless if you define them as a JVM system parameter or as a TVC init parameter. Below is an example how to define as JVM system parameter.
-Dtvc.collaboration.cache.listener.hostName=172.16.16.100 -Dtvc.collaboration.cache.listener.port=2010
The table below shows the additional TVC init parameters that you may want to change in some cases.
| Init Parameter Name | Description | Default Value |
|---|---|---|
tvc.collaboration.cache.listener.portRangeStart |
If you have defined a port explicitly as described above, this parameter can be ignored. Defines the lowest port number that we will try to use. |
4001 |
tvc.collaboration.cache.listener.portRangeEnd |
See above. Defines the highest port number that we might use. |
41020 |
tvc.collaboration.cache.listener.socketTimeoutMillis |
The number of milli-seconds client sockets will wait when sending messages to this listener until they give up. |
2000 |
tvc.collaboration.cache.provider.multicastGroupAddress |
The multi-cast address to be used. |
230.0.0.1 |
tvc.collaboration.cache.provider.multicastGroupPort |
The multi-cast port to be used. |
446 |
tvc.collaboration.cache.provider.timeToLive |
You can control how far the multicast packets propagate by this setting. Using the multicast IP protocol, the timeToLive value indicates the scope or range in which a packet may be forwarded. By convention:
|
1 |
When selecting the HTTP communication approach, each app-server must be able to connect to the other app server(s) in the cluster via HTTP. The implementation will try to identify the URL of the Application server automatically, but, this might in many cases fail due to the setup of load-balancers / proxies and hence you must inform each application server about their own HTTP address. This is done easiest by providing a JVM system parameter to the application server as shown below:
-Dtvc.collaboration.appServerURL=http://the-appserver-machine:8080/enovia
Technia have during the development of the Collaboration component tested on a setup using an Apache HTTPD server acting as a load-balancer and behind having a couple of app servers running Apache Tomcat. All on a Windows 7 host.
The Apache HTTPD server has lately improved their support for web-socket tunneling, and we were using the version 2.4.10.VC11 (64 bit).
The Apache Tomcat versions were 7.0.56 (64 bit).
Below are the configurations we made. Note that we only provide these as examples and you should and might need to adjust them to your needs.
The modules we explicitly enabled were:
proxy_module
proxy_ajp_module
proxy_balancer_module
proxy_wstunnel_module
lbmethod_byrequests_module
lbmethod_bytraffic_module
slotmem_shm_module
Proxy configuration
<Proxy balancer://ws>
BalancerMember ws://inv3373:8080 route=t8009
BalancerMember ws://inv3373:8081 route=t8010
ProxySet lbmethod=bytraffic
ProxySet stickysession=JSESSIONID
</Proxy>
ProxyPass /enovia/collaboration/communication balancer://ws/enovia/collaboration/communication
<Proxy balancer://ajp>
BalancerMember ajp://inv3373:8009 loadfactor=1 route=t8009
BalancerMember ajp://inv3373:8010 loadfactor=1 route=t8010
ProxySet lbmethod=bytraffic
ProxySet stickysession=JSESSIONID
</Proxy>
ProxyPass /enovia balancer://ajp/enovia
Each Tomcat instance were started up using a dedicated start script. Since they were all running on the same machine, we had to configure the ports per instance.
In that start script we configured a number of CATALINA_OPTS as shown
below.
set CATALINA_OPTS=-Dtvc.collaboration.appServerURL=http://localhost:8080/enovia
set CATALINA_OPTS=%CATALINA_OPTS% -Dtomcat.server.port=8005
set CATALINA_OPTS=%CATALINA_OPTS% -Dtomcat.http.port=8080
set CATALINA_OPTS=%CATALINA_OPTS% -Dtomcat.redirect.port=8443
set CATALINA_OPTS=%CATALINA_OPTS% -Dtomcat.ajp.port=8009
The Tomcat server.xml file were changed (note for readability, only changed parts included):
<Server port="${tomcat.server.port}"
<Connector port="${tomcat.http.port}" redirectPort="${tomcat.redirect.port}" />
<Connector port="${tomcat.ajp.port}" protocol="AJP/1.3" redirectPort="${tomcat.redirect.port}" />
<Engine name="Catalina" defaultHost="localhost" jvmRoute="t${tomcat.ajp.port}">
After installing TVC, you must perform three tasks in order to take this feature in to use.
The first task is needed in order to include some functionality within the "emxNavigator.jsp" page (resides in the common folder in your application directory). The only change needed in this file, is to add a single line of code.
Just after the "body" element tag, add the line below (shown in bold):
<body ...>
<%@include file = "/tvc/collaboration/emxNavigator.jspf" %>
...
The second task is needed in order to include some functionality within the "emxNavigatorDialog.jsp" page (resides in the common folder in your application directory). The only change needed in this file, is to add a single line of code.
Just after the "body" element tag, add the line below (shown in bold):
<body ...>
<%@include file = "/tvc/collaboration/emxNavigator.jspf" %>
...
The third task needed is the registration of the Atmosphere servlet that is used for sending notifications from the server to the client (https://github.com/Atmosphere/atmosphere). The following lines should be added to web.xml
<servlet>
<servlet-name>AtmosphereServlet</servlet-name>
<servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
<async-supported>true</async-supported>
<init-param>
<param-name>org.atmosphere.cpr.packages</param-name>
<param-value>com.technia.tvc.collaboration.core.io</param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AtmosphereServlet</servlet-name>
<url-pattern>/collaboration/*</url-pattern>
</servlet-mapping>
In order to use any of the features that requires Exalead you need to install Exalead and set it up for collaboration. To enable Exalead for Collaboration there is a TVC Init parameter that needs to be set.
tvc.collaboration.providerClass=com.technia.tvc.collaboration.core.model.dao.exalead.XlProvider
or using the below short format (preffered).
tvc.collaboration.providerClass=exalead
In order for Exalead to know what data to index for Collaboration the following needs to be added to your Exalead index configuration file.
<BOTYPE name="TVC Collaboration Thread" includes="TVCCollaborationThread" />
<BOTYPEFIELDS name="TVCCollaborationThread">
<FIELD name="TVC_COLLAB_THREAD_CLOUDS" select="program[TVCCollaborationIndex -method getClouds ${OBJECTID}]" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_CONTEXT_ID" select="to[TVC Collaboration Discussion].from.to[TVC Collaboration Discussion Container].from.id" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_FIRST_MSG_SENT_FROM" select="from[TVC Collaboration First Message].to.owner" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_FIRST_MSG_SENT_TO" select="from[TVC Collaboration First Message].to.from[TVC Collaboration Sent To].to.owner" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_HAS_ATTACHMENT" select="from[TVC Collaboration First Message].to.format.hasfile" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_ID" select="id" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_IMPORTANT" select="from[TVC Collaboration First Message].to.attribute[TVC Collaboration Important]" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_LAST_MSG_SENT_FROM" select="from[TVC Collaboration Last Message].to.owner" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_LAST_MSG_SENT_TO" select="from[TVC Collaboration Last Message].to.from[TVC Collaboration Sent To].to.owner" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_PRIVATE" select="attribute[TVC Collaboration Private]" type="BOOLEAN" />
<FIELD name="TVC_COLLAB_THREAD_WORKFLOW" select="attribute[TVC Collaboration Workflow]" type="BOOLEAN" />
<FIELD name="TVC_COLLAB_THREAD_SENT_FROM" select="from[TVC Collaboration Thread Message].to.owner" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_SENT_TO" select="from[TVC Collaboration Thread Message].to.from[TVC Collaboration Sent To].to.owner" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_SUBJECT" select="attribute[TVC Collaboration Subject]" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_SYSTEM_TAGS" select="program[TVCCollaborationIndex -method getSystemTags ${OBJECTID}]" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_UNREAD_USERS" select="program[TVCCollaborationIndex -method getUnreadUsers ${OBJECTID}]" type="STRING" />
<FIELD name="TVC_COLLAB_THREAD_USER_TAGS" select="program[TVCCollaborationIndex -method getUserTags ${OBJECTID}]" type="STRING" />
<FIELD name="TVC_COLLAB_NOTIFICATION_USER_TAGS" select="program[TVCCollaborationIndex -method getNotificationUserTags ${OBJECTID}]" type="STRING" />
<FIELD name="TVC_COLLAB_NOTIFICATION_CATEGORIES" select="program[TVCCollaborationIndex -method getNotificationCategories ${OBJECTID}]" type="STRING" />
<FIELD name="TVC_COLLAB_NOTIFICATION_USER_NAME" select="to[TVC Collaboration Notification].from.owner" type="STRING" />
<FIELD name="TVC_COLLAB_FOLLOWUP_USER_NAME" select="to[TVC Collaboration Followup].from.owner" type="STRING" />
<FIELD name="NAME" select="program[TVCCollaborationIndex -method getMessageSortValueJPO ${OBJECTID}]" type="STRING" fastsort="true" />
</BOTYPEFIELDS>
The discussion functionality allows you to discuss around any type of object in Enovia. The discussion functionality is located in a side panel on the right side of the page content. This allows the users to discuss around an object while still being able to navigate around the different pages of an object.
The panel that contains the discussion functionality is located in the right side of the application. It is injected on the side of the page content so It will stay visible even when navigating around the different pages of an object. The panel is collapsed by default and will be expanded on click.

After clicking on the panel it will be expanded towards the left side and show the discussions for the object that you are currently in context of.

If you disabled the discussion functionality for some object types by configuration the panel will be grayed out and the user will not be able to expand it.
When the user is standing in context of an object that has support enabled for discussions it will be possible to expand the discussion panel in order to view and/or create discussions. The default view of the panel will show a toolbar in the top and below that a list of all the discussions that has been started around the context object.
Each discussion in the list is clickable. The entire discussion will be loaded when a user clicks on it. See next chapter for more details on that.
When a discussion in the list has been clicked it will load the entire discussion in the panel. In this view the user will be able to see all the messages in the discussion and also have the ability to reply to it.
In order to create a new discussion you use the action in the top toolbar (plus sign). That will launch a form that allows you enter the data needed to create a new discussion.

The following data can be entered:
The subject of the discussion
A flag that indicates if the discussion is important or not (visual indication)
A list of recipients. If this is set then the message will be "private" and only visible to these users. Otherwise it will be public and visible to everyone that has access to this object.
A set of user "tags". Currently this is only used for display but in coming releases it could be used for loading discussions based on tags.
Message content
Attachments
A user can reply to a discussion using the reply button located at the top or bottom of the discussion. The reply form is the same as the one you use when you create a new discussion but you are not able to set a subject (see chapter above on creating a new discussion)

Using tvc.properties create/reply discussion form fields can be configured to be hidden except Subject and Message fields.
| Property | Description | Default Value |
|---|---|---|
tvc.collaboration.showPrivate |
To show Private Filed |
false |
tvc.collaboration.showImportant |
To show Important Filed |
true |
tvc.collaboration.showRecipient |
To show Recipient Filed |
true |
tvc.collaboration.showWatcher |
To show Watcher Filed |
true |
tvc.collaboration.showUserTags |
To show User Tags Filed |
false |
tvc.collaboration.showContextObjects |
To show Context Objects Filed (shown for multiple context objects) |
true |
tvc.collaboration.showDropzone |
To show Dropzone Filed |
true |
The ability to discuss around objects can be configured on the server.
This is done in a file called TVCDiscussionConfig.xml that is placed in
/WEB-INF/classes/TVCDiscussionConfig.xml. If you skip to have this
configuration file the users will be able to discuss around ANY object
in Enovia with default settings.
Below is an example configuration file that shows the supported elements and their location.
<DiscussionConfigs>
<ConfiguredTypes>
<Type derived="false" status="disabled">type_MechanicalPart</Type>
<Type derived="false" status="expand">type_HardwarePart</Type>
<Type derived="false" status="enabled">type_NutPart</Type>
</ConfiguredTypes>
<DiscussionConfig for="Part" if="attribute[Usage] != Abc">
<TagHandler className="..."/>
<Tags>
<Object>
<Tag select="type" key="kind"/>
<Tag select="name" key="identifier"/>
<Tag select="revision"/>
<Tag select="current" key="state"/>
</Object>
<User>
<!-- user specific tag. used for custom context action and filter. -->
<Tag key="xfav" value="false" />
</User>
</Tags>
<ContextHandler>
<Macro>${TYPE}, ${NAME} : ${REVISION}</Macro>
<URL>/common/emxNavigator.jsp?objectId=${OBJECTID}</URL>
</ContextHandler>
<Cloud>true</Cloud>
<Toolbar>tvc:menu:tvx:collaboration/CustomToolbar.xml</Toolbar>
<Filter ref="tvc:collaborationfilter:tvx:collaboration/Product.xml" />
</DiscussionConfig>
<ObjectIdResolver/>
<OrganizationResolver/>
<ContextInfoResolver/>
</DiscussionConfigs>
<DiscussionPanelThreadActions>tvc:menu:tvx:collaboration/CustomMenu.xml</DiscussionPanelThreadActions>
<InboxThreadActions>tvc:menu:tvx:collaboration/CustomMenu.xml</InboxThreadActions>
The <ConfiguredTypes> tag allows you to configure the discussion behavior or disable it for different types in the system. The child elements for this are <Type>
This element allows you to control the discussion behavior for a specific type. The attribute "derived" will apply the setting for all derived types as well. The "status" attribute is used to "enable", "disable" or "expand" (enabled and automatically opened side panel)
The <DiscussionConfig> element is used if you want to configure the discussion behavior for a type of object. You can have any amount of this element in your configuration. This is currently used in order to configure system generated tags that are saved on each discussion.
Allows you to point out a class that will have the logic for writing
system generated tags on discussions. The complete name of the class to
use is added to the attribute called "className". That class has to
implement the interface com.technia.tvc.collaboration.core.model.tag.TagHandler.
This element allows you to generate system tags added to discussions. You can add any amount of child elements with the name <Tag>. On that element the "select" attribute is used for adding a select expression for fetching values to save and the "key" element specifies the key to save it on. All tags are saved together as a JSON string in an attribute.
This element can be used to configure custom settings for the context information related to an object (used to display a link to the context object for a discussion/workflow). The child element <Macro> is used to configure the "display name" and the <URL> element is used to configure the URL to the context object.
Configures if clouds should be generated. Clouds are used to label messages with one or more entities (other than the context object). Read more about Clouds in later chapters.
This element is required only when custom parameters instead of objectId passed to load discussions. Allows you to point out a class that will have the logic for returning objectId from the parameters.
Default implementation resolves objectId based on type, name, revision
and vault values separated by &. (type=Part&name=10001&revision=1&vault=Production).
The complete name of the class to use is added to the attribute called
"className". That class has to implement the interface
com.technia.tvc.collaboration.core.model.dao.enovia.config.ObjectIdResolver.
This element allows to return the Organization of the user, which can be used to show along with user name is Collaboration component. When there are multiple Organizations returned for the user, multiple entries will be shown in the autocomplete for the given user each for each organization.
Default implementation resolves Organizations based on Member relationship to Organization by "Organization Name" attribute value.
The complete name of the class to use is added to the attribute called
"className". That class has to implement the interface
com.technia.tvc.collaboration.core.model.dao.enovia.config.OrganizationResolver.
This element also supports an attribute called "select" which can be selectable to get Organization value.
<OrganizationResolver select="attribute[Organization Name]"/>.
From/Sender user organization is resolved using the implementation of OrganizationResolver’s getSenderOrganizations.
This property has to be enabled for Organization
tvc.collaboration.showOrganization=true.
Following properties can be used to tune autocomplete field.
| Property | Description | Default Value |
|---|---|---|
tvc.collaboration.showOrganization |
To enable Organizations inside collaboration component |
false |
tvc.collaboration.autocomplete.startWith |
Whether search criteria should match starting instead of contains |
false |
tvc.collaboration.autocomplete.minLength |
No. of characters after autocomplete initiated |
2 |
tvc.collaboration.autocomplete.loadThrottle |
No. of milliseconds after autocomplete initiated |
400 |
tvc.collaboration.autocomplete.caseSensitive |
Whether search criteria should be case sensitive |
false |
public class TestOrganizationResolver extends DefaultOrganizationResolver {
@Override
public List<Organization> getOrganizations(String user) throws TVCException {
return super.getOrganizations(user);
}
@Override
public List<Organization> getSenderOrganizations(OrganizationContext context) throws TVCException {
//context contains Message, previously resolved Organizations, contextIds and Env
return super.getSenderOrganizations(context);
}
}

This element is similar to contextHandler but instead of to a single CollaborationConfig (i.e DiscussionConfig or WorkflowConfig) this is applicable to all CollaborationConfigs. This element can be used to configure custom settings for the context information related to an object (used to display a link to the context object for a discussion/workflow).
The child element <Macro> is used to configure the "display name" and
the <URL> element is used to configure the URL to the context object.
Default implementation resolves display name from <Macro> ${type},
${name} : ${revision}</Macro> and context URL from <URL>
/common/emxNavigator.jsp?objectId=${OBJECTID}</URL>.
The complete name of the class to use is added to the attribute called
"className". That class has to implement the interface
com.technia.tvc.collaboration.core.model.context.ContextInfoResolver.
Following properties can be used to configure the behavior of context path.
| Property | Description | Default Value |
|---|---|---|
tvc.collaboration.contextpath.popup |
Whether context path should be opened popup |
false |
tvc.collaboration.contextpath.popup.width |
Width of context path popup window in pixel |
900 |
tvc.collaboration.contextpath.popup.height |
Height of context path popup window in pixel |
700 |
Messages are often created in context of an object. It can later on be found when navigating to that particular object and then opening the discussion panel. The cloud concept allows labeling of messages with other entities. It can be other objects or fictive clouds.
Example: Let’s presume we are in the apparel industry. We are working with seasons and each season we launch a number of products which in turn consists of parts. When a message is created on a product it should be labeled with the season cloud. Messages created on a part should be included in both the product and season cloud. Once users navigate to the product or season they can see discussions related to the product/season cloud.
The Cloud Locator is used to define the cloud(s) a particular object is part of. It locates the clouds based on object ids.
The locator is used when creating new messages that have clouds enabled (done in the DiscussionConfig). For searching it also used when the "searchBase" is set to cloud. A Clouds Locator is required to be implemented and registered if using the cloud concept.
Cloud Locator interface:
public interface CloudLocator {
Collection<Cloud> getClouds(Collection<Identifier> ids);
}
Note that the method takes a collection of ids. Messages can be created in context of several objects, hence the collection. The clouds returned should consider all the ids.
Example implementation:
public class ExampleCloudLocator implements CloudLocator {
private static final Logger logger = Logger.getLogger(ExampleCloudLocator.class);
@Override
public Collection<Cloud> getClouds(Collection<Identifier> ids) {
Collection<Cloud> clouds = new ArrayList<Cloud>();
try {
DataExtractor extractor = new DataExtractor()
.addId(EnoviaIds.asList(ids))
.addStatement(Statement.ID, Statement.TYPE, Statement.NAME);
Result result = extractor.perform();
Iterator<SelectedData> itr = result.iterator();
while (itr.hasNext()) {
SelectedData data = itr.next();
String id = data.getSelectValue(Statement.ID);
String type = data.getSelectValue(Statement.TYPE);
String name = data.getSelectValue(Statement.NAME);
if ("Product".equals(type)) {
clouds.add(Cloud.getIntance(id, String.format("Product %s", name)));
} else if ("Part".equals(type)) {
clouds.add(Cloud.getIntance(id, String.format("Part %s", name)));
// Add to product cloud
Product product = getProduct(id);
if (product != null) {
clouds.add(Cloud.getIntance(product.getId(),
String.format("Product %s", product.getName())));
}
}
}
} catch (TVCException e) {
logger.error(e, e);
}
return clouds;
}
private Product getProduct(String partId) throws TVCException {
// Code omitted
}
}
Register the locator when application server starts in your TVC Plugin class:
public final class AcmePlugin extends TVCComponentBase {
@Override
public void init() {
CloudService.setLocator(new ExampleCloudLocator());
}
}
When a discussion is created and sent to some users all of them are automatically subscribed (started watching) to the thread. Any reply to the thread is notified to all the subscribers/watchers of the thread.
Any time user can unsubscribe or stop watching the thread clicking the stop watching. Any time use can start watching the thread by clicking start watching.

Start watching / Stop watching action can be performed in inbox as well.

When a thread is replied number of watchers to the thread is shown. Clicking the watcher count will show all users watching the thread.

By default the reply form is opened in "popups". This is good for visibility since the form gets all focus. However this prevents the users from reading the previous replies while doing a new reply. So if it is more important to be able to see the entire discussion while replying we have added a new rendering mode called "single page mode". This will do the following two changes to the UI:
The reply form will not be opened in "popups". It is instead rendered directly in the top of the discussion you are replying to (both inbox and side panel).
All discussions are expanded/viewed directly in the same "page" when you click on them. (Instead of reloading the whole page with the clicked discussion)
This mode is enabled by setting the following parameter to true.
| Property | Description | Default Value |
|---|---|---|
tvc.collaboration.discussionpanel.mode.singlePage |
Enable single page mode |
false |
At some events that occur in the discussion functionality there are "notifications" sent out to users that are involved in a discussion in one or more ways. If someone starts a discussion around an object then the owner of that object will get a notification. Users will also get notifications when another user is replying to a discussion or message that user started.
These notifications are sent to the user instantly when an event is occurring. We have two ways of notifying the users, one called "Inline notifications" and one called "Web notifications". These work in the same way but are displayed in different ways.
Inline notifications are rendered in the top right corner of the browser window when an event occurs.
Inline notification
Web notifications are displayed on the computer desktop, outside of the browser window. The benefit of this is that you will notice it even if your browser window is minimized. This is currently not supported in Internet Explorer and really old versions of the other browsers. Clicking the notification will show the browser window and open My Space.
Web notification
When clicking on the icon in the global toolbar it will open something called "My Space" as a big overlay in the browser window. "My Space" contains a set of different functionality related to the user and the TVC Collaboration feature. Inbox and Profile are the default preconfigured "My Space" Actions. The functionality that is displayed on first load is called "Inbox" and is described in the next chapter. First load "My Space" Action can be rearranged TVCDiscussionConfig.xml.
The inbox is a functionality used for displaying all notifications that a user has received. It has a layout that is similar to a mail application.

Figure: Inbox displaying notifications
When MySpaceConfig is modified to include other "My Space" Actions. It is mandatory to include default Actions as well. Actions can be reordered. All Inbox derived actions can be repeated with different configuration but with unique action id. Actions can also be grouped under different labels.
<MySpaceConfig>
<!-- short form -->
<!-- <InboxAction/> -->
<!-- custom inbox with custom id -->
<!-- <InboxAction id="some-unique-action-id"/> -->
<InboxAction>
<Font>fa-inbox</Font>
<Label>Inbox</Label>
<Label locale="de">Posteingang</Label>
<Label locale="sv">inkorg</Label>
<Header>Inbox</Header>
<Header locale="de">Posteingang</Header>
<Header locale="sv">inkorg</Header>
<GroupLabel>Other</GroupLabel>
<!-- optional advanced feature configurations. more details below. -->
<ThreadActions className="com.technia.tvc.collaboration.core.test.TestDPLocalThreadActionsProvider">tvc:menu:tvx:collaboration/CustomMenu.xml</ThreadActions>
<Filter ref="tvc:collaborationfilter:tvx:collaboration/Inbox.xml"></Filter>
<JavaScript src="/tvx/js/custom.js"></JavaScript>
<StyleSheet src="/tvx/css/custom.css"></StyleSheet>
<AjaxService service="customService"></AjaxService>
<Template id="customTemplate" src="/tvx/template/custom.jsp"></Template>
<ContextMenu ref="tvc:menu:tvx:collaboration/CustomMenu.xml"></ContextMenu>
</InboxAction>
</MySpaceConfig>
"ToMeAction" is a predefined custom Inbox Actions which depends on Exalead that can used in "My Space". This action shows the inbox items sent to the context user as Recipient.

"UnreadAction" is a predefined custom Inbox Actions which depends on Exalead that can used in "My Space". This action shows the inbox items which are not read by the context user.

"SystemNotificationAction" is a predefined custom Inbox Actions which depends on Exalead that can used in "My Space". This action shows the inbox items which are system generated. System generated Inbox items are identified using System Tags. Refer the consecutive chapters for configuration.

Other than user generated, messages can be created in result of system event or trigger actions.
DAOFactory factory = DAOFactory.getInstance();
DiscussionConfigDAO configDAO = factory.getDiscussionConfigDAO();
MessageDAO messageDAO = factory.getMessage();
Message message = new Message();
message.addContextId(configDAO.resolveId("14668.27509.6640.54321"));
message.setFrom(factory.getPerson().read("Adam Sandler"));
message.setImportant(true);
message.setSubject("Fastener Part-EV-0000020-A released");
message.setMessage("Fastener Part-EV-0000020-A released using ECO Eco-00003");
message.setRepliable(false);
//sample tag to denote system notification
message.addSystemTag(Tag.getIntance("event", "trigger"));
//message.addSystemTag(Tag.getIntance("Event", "system"));
message.addRecipient(new Recipient(RecipientType.TO, new Person("Jennifer Aniston")));
Environment env = RequestUtils.newEnv(request);
messageDAO.create(message, env);
Collection<Notification> notifications = messageDAO.getNotifications(message.getId(), env);
ClientBroadcasterFactory.getInstance().getBroadcaster().broadcast(notifications);
SystemNotficationAction should be configured with Filter (see chapter 10) with invisible FilterItem which matches the above generated System tag to filter System Notifications.
Other Inbox Actions as well should be configured with Filter which excludes System Notifications.
<MySpaceConfig>
<SystemNotificationAction>
<Filter applyOnLoad="true" showOnLoad="true" visibleRowCount="1">
<Row visible="false">
<FilterItem>
<Operator>EQUAL</Operator>
<LogicalOperator>OR</LogicalOperator>
<MapsTo>
<Tag>
<Name>event</Name>
</Tag>
</MapsTo>
<Values>
<Value selected="true">
<SubmitValue>trigger</SubmitValue>
<DisplayValue>trigger</DisplayValue>
</Value>
</Values>
<UIControl>text</UIControl>
</FilterItem>
</Row>
</Filter>
</SystemNotificationAction>
<!-- System Notifications to be excluded in other Inbox Actions -->
<InboxAction>
<Filter applyOnLoad="true" showOnLoad="true" visibleRowCount="1">
<Row visible="false">
<FilterItem>
<Operator>NOT_EQUAL</Operator>
<LogicalOperator>AND</LogicalOperator>
<MapsTo>
<Field>
<Name>TVC_COLLAB_THREAD_SYSTEM_TAGS</Name>
</Field>
</MapsTo>
<Values>
<Value selected="true">
<SubmitValue>event</SubmitValue>
<DisplayValue>event</DisplayValue>
</Value>
</Values>
<UIControl>text</UIControl>
</FilterItem>
</Row>
</Filter>
</InboxAction>
</MySpaceConfig>
"FollowupAction" is a predefined custom Inbox Actions which depends on Exalead that can used in "My Space". This action shows the inbox items which are followed by the context user.
Following Inbox items using Context Menu:

Followup showing followed item by the context user:

The profile page has functionality for doing various types of actions related to the user. It is used for uploading an avatar image that will be displayed in discussions and for controlling user preferences.

Figure: Profile Page
"ExternalAction" is a predefined custom Inbox Actions which can used in "My Space". This action can be used to host External web application inside iframe of Collaboration component.
Bing.com as MySpace Action:

<MySpaceConfig>
<ExternalAction id="bing">
<Label>Bing</Label>
<Font>fa-search</Font>
<Header>Bing</Header>
<Href>http://bing.com</Href>
</ExternalAction>
<ExternalAction id="verge">
<Label>Verge</Label>
<Header>The Verge</Header>
<Href>http://www.theverge.com/</Href>
</ExternalAction>
</MySpaceConfig>
Inbox will have following context actions
| Action | Description |
|---|---|
Mark as Read |
Marks the context selected Inbox item as read |
Mark as unread |
Marks the context selected Inbox item as not read |
Follow up |
Marks the context selected Inbox item as being followed |
Unfollow up |
Removes the context selected Inbox item being followed |
Categorize |
Contains sub actions to add categories and clear categories for the selected inbox item |

Category’s label can be changed using "All Categories…" context action.

It is possible to add additional context action commands to Inbox Context Menu. This customization can be done with xml configuration.
The additional context actions for the specific inbox can be configured like this (placed inside a
<InboxAction> or something that is derived from that).
<MySpaceConfig>
<InboxAction>
<ContextMenu ref="tvc:menu:tvx:collaboration/CustomContextMenu.xml"></ContextMenu>
</InboxAction>
</MySpaceConfig>

All the different configuration elements share the same abilities of configuration. You can ADD commands using a TVC XML menu configuration.
By adding a reference to a TVC XML menu configuration it is possible to add one or more actions. This uses the same menu configuration as other TVC (not everything supported though). Below is an example configuration:
<Menu>
<Command>
<Label>Welcome</Label>
<Href>
<![CDATA[
javascript:alert('Hello!');
]]>
</Href>
</Command>
<Command>
<Label>Favourite</Label>
<Href>
<![CDATA[
javascript:$inbox.updateUserTag($notification, 'xfav', 'true', false);
]]>
</Href>
<Setting name="enablerScript">
<![CDATA[
(function(notification, name, value){
var tag = notification.userTags.filter(function(tag) {
return tag.name === name;
});
return tag.length == 0 || tag[0].value== 'false';
})(notification, 'xfav');
]]>
</Setting>
<Setting name="visibilityScript">
<![CDATA[
(function($inbox, id){
return $inbox.getActionId() !== id;
})($inbox, 'favourite-inbox');
]]>
</Setting>
</Command>
<Command>
<Label>Unfavourite</Label>
<Href>
<![CDATA[
javascript:$inbox.updateUserTag($notification, 'xfav', 'false', $inbox.getActionId() === 'favourite-inbox');
]]>
</Href>
<Setting name="enablerScript">
<![CDATA[
$inbox.tagEnablerScript(notification, 'xfav', 'true');
]]>
</Setting>
</Command>
</Menu>
Use the <Image> element to control the action
icon. Action command’s JavaScript executed on command click. Use the
<Label> element for adding a text to the action.
Href
Here $inbox', '$notification' are script objects in scope when action command executes. other scope objects are '$event', 'notification', '$command'.
updateUserTag is method available on $inbox object.
first parameter is $notification (selected item)
second parameter is custom tag. it can be any valid tag name.
third parameter is custom tag value. it can be any valid tag value.
fourth parameter is boolean. 'true' will remove the selected item from view. 'false' does nothing.
ex: $inbox.getActionId() === 'favourite-inbox' evaluates to true or false. when true, selected item is removed from view. when current inbox is "favourite-inbox" and unfavouriting a item will remove the item from view.
<Command>
<Href>
<![CDATA[
javascript:$inbox.updateUserTag($notification, 'xfav', 'true', false);
]]>
</Href>
</Command>
<!-- or -->
<Command>
<Href>
<![CDATA[
javascript:$inbox.updateUserTag($notification, 'xfav', 'true', $inbox.getActionId() === 'favourite-inbox');
]]>
</Href>
</Command>
enablerScript
setting to a custom script function to show the command 'enabled' or 'disabled'. The function can use buitin scope objects like '$notification', 'notification', '$component' and '$inbox'.
tagEnablerScript is method available on $inbox object. returns true if given notification contains the given tag and value.
first parameter is notification (selected item data)
second parameter is custom tag. it can be any valid tag name.
third parameter is custom tag value. it can be any valid tag value.
<Command>
<Setting name="enablerScript">
<![CDATA[
(function(notification, name, value)
var tag = notification.userTags.filter(function(tag) {
return tag.name === name;
});
return tag.length == 0 || tag[0].value== 'false';
})(notification, 'xfav');
]]>
</Setting>
</Command>
<!-- or -->
<Command>
<Setting name="enablerScript">
<![CDATA[
$inbox.tagEnablerScript(notification, 'xfav', 'true');
]]>
</Setting>
</Command>
visibilityScript
setting to a custom script function to change the visibility of the command. The function can use buitin scope objects like '$notification', 'notification', '$component' and '$inbox'.
below favourite command is visible for all inboxes except inbox named 'favourite-inbox'
<Command>
<Setting name="visibilityScript">
<![CDATA[
(function($inbox, id){
return $inbox.getActionId() !== id;
})($inbox, 'favourite-inbox');
]]>
</Setting>
</Command>
Instead of inline script functions in additional inbox context menu actions, an external script file can be included in My Space. using following configurations. Along with custom scripts, custom CSS, AjaxService and Custom Template resources also can be included as below.
<JavaScript>, <StyleSheet>, <AjaxService> and <Template> element can be repeated to support multiple resource inclusion.
<MySpaceConfig>
<InboxAction>
<JavaScript src="/tvx/js/custom.js"></JavaScript>
<StyleSheet src="/tvx/css/custom.css"></StyleSheet>
<AjaxService service="customService"></AjaxService>
<Template id="customTemplate" src="/tvx/template/custom.jsp"></Template>
</InboxAction>
</MySpaceConfig>
From a table page, you can add a column that will show an icon when a discussion exists for the object. Clicking on the icon brings up the discussion panel.
To enable this column in your table, add a column like shown below:
<Table>
...
<Column>
<Name>discussion-link</Name>
<ColumnType>discussion-link</ColumnType>
</Column>
</Table>
If the table is defined as a system table, use the setting "Column Type" to achieve the same.
Below is a screenshot illustrating how the icon will appear in case there are discussions available.

Just like in ENOVIA, Collaboration can be configured in external web applications:
Web App should reference following TVC endpoint in Script tag
<html>
....
<body>
.....
<script data-collaboration="path/integration.js" type="text/javascript"
src="http://<server>/enovia/tvc/collaboration/tvcCollaborator.jsp"></script>
</body>
</html>
TVC Collaboration Integration URL:
tvc/collaboration/tvcCollaborator.jsp
Attribute data-collaboration="path/integration.js" points to hosting web application’s integration scripts.
Web App invokes Collaboration script with configuration details.
//integration.js
// toolbarId: element id where notification icon injected
// contentId: element id where discussion panel injected as sibling
// env: optional custom information. can be obtained in server side custom code.
var collaboration = window.getCollaboration();
collaboration.config({ toolbarId: 'toolbar', contentId: 'main-content', env: { 'name': 'sk', 'external': 'skclusive' } });
Web App registers for collaboration ready event which is passed with collaborator interface.
//integration.js
collaboration.ready(function ($collaborator) {
console.log("collaboration is ready to be executed");
$("#open-discussion").click(function () {
var type = $("#type").val();
var name = $("#name").val();
var revision = $("#revision").val();
var params = "type=" + type + "&name=" + name + "&revision=" + revision;
$collaborator.openCollaborationPanel([params]).then(function (value) {
console.log("Discussion Panel is " + (!value ? "not " : "") + "opened for '" + params + "'");
});
});
$("#close-discussion").click(function () {
$collaborator.closeCollaborationPanel().then(function () {
console.log("closeDiscussionPanel successfully");
});
});
$("#open-myspace").click(function () {
$collaborator.openMySpace().then(function () {
console.log("openMySpace successfully");
});
});
$("#close-myspace").click(function () {
$collaborator.closeMySpace().then(function () {
console.log("closeMySpace successfully");
});
});
});
It is possible to add and remove action commands from both the discussion panel top toolbar and the actions that is related to the discussion thread (inbox and side panel). This can be done globally but also depending on the discussion context. This customization can be done with xml configuration AND/OR in JAVA code.
Thread actions can be configured globally and is done using the
following elements (placed directly under the <DiscussionConfigs>
element). This will then be used for ALL discussion configurations.
<DiscussionPanelThreadActions className="com.technia.tvc.collaboration.core.test.TestDPGlobalThreadActionsProvider">tvc:menu:tvx:collaboration/CustomMenu.xml</DiscussionPanelThreadActions>
<InboxThreadActions className="com.technia.tvc.collaboration.core.test.TestIBGlobalThreadActionsProvider">tvc:menu:tvx:collaboration/CustomMenu.xml</InboxThreadActions>
The first one will change the thread actions in the inbox and the second one for the side panel. See more details later in this document.
Thread actions and top toolbar actions can also be configured for different discussion configurations. This means you can have different actions depending on what configuration is used. You can also configure actions for the different My Space inboxes.
The top toolbar for the side panel is configured like this (placed
inside a <DiscussionConfig> element).
<Toolbar className="com.technia.tvc.collaboration.core.test.TestToolbarProvider">tvc:menu:tvx:collaboration/CustomToolbar.xml</Toolbar>
Thread actions for side panel are configured like this: (placed inside a <DiscussionConfig> element)
<ThreadActions className="com.technia.tvc.collaboration.core.test.TestDPLocalThreadActionsProvider">tvc:menu:tvx:collaboration/CustomMenu.xml</ThreadActions>
Thread actions for an inbox are configured like this: (placed inside a
<InboxAction> or something that is derived from that)
<ThreadActions className="com.technia.tvc.collaboration.core.test.TestDPLocalThreadActionsProvider">tvc:menu:tvx:collaboration/CustomMenu.xml</ThreadActions>
All the different configuration elements share the same abilities of configuration. You can ADD commands using a TVC XML menu configuration AND/OR add or remove commands using Java code.
By adding a reference to a TVC XML menu configuration it is possible to add one or more actions. This uses the same menu configuration as other TVC (not everything supported though). Below is an example configuration:
<Menu>
<Command>
<Href>http://www.technia.com</Href>
<Image>${ROOT_DIR}/xbom/xbl/images/create.gif</Image>
<FontIcon>fa fa-thumbs-up</FontIcon>
<Alt>tooltip here</Alt>
<WindowHeight>400</WindowHeight>
<WindowWidth>600</WindowWidth>
</Command>
<Command>
<Href>javascript:alert('Clicked!');</Href>
<FontIcon>fa fa-beer</FontIcon>
<Label></Label>
<Alt>tooltip here</Alt>
</Command>
</Menu>
Use either the <Image> or <FontIcon> element to control the action
icon. Action commands are by default opened as a popup but it is also
possible to specify a JavaScript to be executed on click. Use the
<Label> element for adding a text to the action (not used for top
toolbar).
If more complex logic is needed to control what actions to show it is possible to use JAVA code to achieve this. It is done by adding an attribute called className that points to a custom JAVA class that extends one of the following classes:
com.technia.tvc.collaboration.core.model.dao.enovia.menu.DefaultToolbarProvider com.technia.tvc.collaboration.core.model.dao.enovia.menu.DefaultDiscussionPanelThreadProvider com.technia.tvc.collaboration.core.model.dao.enovia.menu.DefaultInboxThreadProvider
In the custom Java class it is possible to override the following method:
public Menu getMenu(MenuContext ctx)
That method will allow you to return the menu to use. By calling the super class method it is possible to get the default menu. The MenuContext object contains information like user, thread and context.
It is possible to configure something called advanced filter in order to control the data loaded for this component. This type of filtering is able to load and filter on data that has been indexed by Exalead. This can be used to filter out both notifications in the inbox and discussion threads in the side panel. These filters can be hidden or visible so that the user can change values in the UI.

In order to enable a filter you can reference a filter configuration in your TVCDiscussionConfig.xml file like this.
<Filter ref="tvc:collaborationfilter:tvx:collaboration/Product.xml" />
<Filter> elementThe base element for the actual filter configuration is the <Filter> element. That one has a number of attributes that can be used to control some behavior for the entire filter.
<Filter showOnLoad="true" visibleRowCount="3" searchBase="cloud"
visible="true">
| Attribute | Description | Default Value |
|---|---|---|
showOnLoad |
Show filter on load or not (if set to false the user will have to click the filter icon to show the filter |
true |
visibleRowCount |
How many filter rows (rows described later) that will be showed on load. Visibility of rest can be toggled by the user. |
|
searchBase |
See chapter about Cloud |
|
visible |
Whether the filter should be shown or be hidden |
true |
<Row> elementEach filter can have any amount of rows. A row corresponds to a row in the filter user interface. Each row can have a label set and that will then be rendered to the far left. Each row can then have a single or multiple filter items. A row can be hidden using the "visible" attribute.
<Row visible="true">
<Label>Anything</Label>
<FilterItem>..</FilterItem>
<FilterItem>..</FilterItem>
</Row>
<FilterItem>A <FilterItem> represents an element that can be used to filter data
(texfield, dropdown, button etc.). Each filteritem maps against one or
multiple values that has been indexed by Exalead. Below is a complete
example of a filteritem. Each element described after the example
<FilterItem>
<Operator>NOT_EQUAL</Operator>
<LogicalOperator>AND</LogicalOperator>
<MapsTo>
<Tag>
<Name>category</Name>
</Tag>
<Field>
<Name>THREAD_FIRST_MSG_SENT_FROM</Name>
</Field>
</MapsTo>
<Values>
<Value>
<SubmitValue />
<DisplayValue />
</Value>
<Value selected="true">
<SubmitValue>production</SubmitValue>
<DisplayValue>Production</DisplayValue>
</Value>
<Value>
<SubmitValue>development</SubmitValue>
<DisplayValue>Development</DisplayValue>
</Value>
</Values>
<UIControl>dropdown</UIControl>
</FilterItem>
<Operator>Can be used to control what operator to use for this field item. It is not mandatory to specify this.
EQUAL (default)
NOT_EQUAL
LESS_THAN
GREATER_THAN
<LogicalOperator>Can be used to control what logical operator to use for this field item. Not mandatory to set this.
OR (default)
AND
<MapsTo>This element is used to map this field against either tags or indexed fields in Exalead. In order to filter on tags one or more <Tag> elements are used and in order to filter on fields one or more <Field> elements are used.
<MapsTo>
<Tag>
<Name>category</Name>
</Tag>
<Field>
<Name>THREAD_FIRST_MSG_SENT_FROM</Name>
</Field>
</MapsTo>
user specific custom tag filter
<FilterItem>
<Operator>EQUAL</Operator>
<LogicalOperator>AND</LogicalOperator>
<MapsTo>
<Tag user="true">
<Name>xfav</Name>
</Tag>
</MapsTo>
<Values>
<Value selected="true">
<SubmitValue>true</SubmitValue>
<DisplayValue>Favourite</DisplayValue>
</Value>
</Values>
<UIControl>textbutton</UIControl>
</FilterItem>

<UIControl>This element is used to control what type of UI control to use for this field. Supported values are:
Dropdown list with possibility to select ONE value.
Dropdown list with possibility to select MULTIPLE values.
Text field where user can enter any text
Yes/No buttons
Buttons containing custom values. (Each value renders as a button)
Some of these elements require you to configure the values that can be used. See next section
<Values>This element is used to configure the allowed values for a <UIControl>.
All UI controls except BOOLEANBUTTON and TEXT requires one or more
values. Each value has a submit-value that is sent to the server and a
display-value that is rendered for the user. A value can be configured
to be default selected with the attribute "selected"
<Values>
<Value>
<SubmitValue>MHK</SubmitValue>
<DisplayValue>MHK</DisplayValue>
</Value>
<Value selected="true">
Values can also be loaded through Java code like this.
<Values valueHandler="com.technia.tvc.example.valuehandler.ObjectIdValueHandler"/>
The value handler class needs to implement the
com.technia.tvc.collaboration.core.model.dao.enovia.config.ValueHandler
(deprecated) interface.
ValueHandler interface has been deprecated in favour of
com.technia.tvc.collaboration.core.model.dao.enovia.config.FilterValueHandler.
Categories FilterItem Configuration
<FilterItem>
<Label>Categories</Label>
<Operator>EQUAL</Operator>
<LogicalOperator>AND</LogicalOperator>
<Type>category</Type>
<UIControl>multiselectdropdown</UIControl>
</FilterItem>
Date formats inside collaboration user interface can be configured to display custom date format.
Collaboration component uses moment.js version 2.4.0 (http://momentjs.com/) for date/time display. So supporting formats documented here http://momentjs.com/docs/#/displaying/format/ and also a custom format "fromNow" equivalent to moment.js’s "fromNow" functionality.
Below properties can be configured to format the date used in sections of the collaboration component.
| Property | Description | Default Value |
|---|---|---|
tvc.collaboration.inbox.list.dateFormat |
Date format used in Inbox items view |
fromNow |
tvc.collaboration.inbox.detail.dateFormat |
Date format used in Inbox preview/detail view |
YYYY-MMMM-DD, HH:mm:ss |
tvc.collaboration.discussion.list.dateFormat |
Date format used in sidepanel threads view |
fromNow |
tvc.collaboration.discussion.detail.dateFormat |
Date format used in sidepanel thread detail view |
fromNow |
Additional property configurations for Collaboration
| Property | Description | Default Value |
|---|---|---|
tvc.collaboration.discussion.important.latest |
Whether to show thread level important flag from latest message. (inbox and side panel) By default, important flag of first message is shown. |
false |
tvc.collaboration.configured.locales |
comma separated locales configured for collaboration string resources to avoid dual languages in view because of momentJS Ex: en,sv,fr |
en |
tvc.collaboration.fallback.locale |
Fallback locale If user’s preferred language is not within configured locales. This is to avoid dual languages in view because of momentJS. Ex: sv |
en |
tvc.collaboration.initialavatar |
Default user avatars that are based on the first letter of their name and a random color. If disabled all users will instead have the same default avatar that is a static image. |
true |
The TVC Wiki component adds the ability to create and edit any number of interlinked pages in ENOVIA using a simplified markup language or a Rich Text editor that presents the user with at "what-you-see-is-what-you-get" editing area. The main features of the Wiki are:
Create and edit wiki pages
Markup editor
Rich Text editor
Interlinking between pages
Linking to external web pages
Linking to ENOVIA objects
Adding attachments
Adding Reference Objects (ENOVIA objects)
Displaying image attachments on a page
Page versioning
Page history
Sub pages
Free text search of wiki page content
Commenting pages
Dynamic menu tree
Breadcrumbs
Multiple wikis
Global wiki
Context wikis (connected to ENOVIA objects)
Wiki Administration
The wiki can be used in different contexts. You can have a "global" Wiki that is accessible from the global toolbar and you can also add the ability to get a separate "context" wiki for each ENOVIA object instance of configured types (Projects, Workspace, Parts…).
The global wiki is launched from a command in the global toolbar. There can only be one global wiki in the system and it is not related to any specific ENOVIA object instance.
By adding the TVC Wiki command to any ENOVIA type menu or tab you enable the ability to have a separate Wiki connected to each instance of that object type.
You can also use the context wiki in a "slim" mode. When using this mode some of the features are stripped away. You will only be able to have ONE page in each wiki so the left menu tree is removed. Some of the tabs and commands are also removed in this mode.
So basically you get a very slimmed wiki with only one page that has attachment and comment functionality.
The following is a list of the minimum requirements for the installation of the Wiki. If your system is different, consult Technia before installing.
ENOVIA V6R2009x or higher
Supported Browsers:
Internet Explorer 9-11
Firefox 27.0 and later
Application Server according to the ENOVIA core product requirements
The database schema includes a Command that can be used to access the Wiki. This command is called "TVC Wiki". If this command is added to the global toolbar it will enable the Global Wiki. If it is added in context of an ENOVIA type (in type menu or as a TVC Tab) it will enable the Wiki for that type. If you want to use the "slim" version of the wiki as a context wiki you use the command called "TVC Wiki Slim".
In order to enable users to start using the Wiki functionality there are three different roles that can be assigned depending on what access level should be given.
| Role | Description |
|---|---|
TVC Wiki Viewer |
Is allowed to view and comment on wiki pages |
TVC Wiki Author |
Same access as TVC Wiki Viewer but can also create and edit wiki pages |
TVC Wiki Administrator |
Same access as TVC Wiki Author but can also delete wiki pages and comments |
This access is set in several xml configurations (commands) for the component so they can easily be changed by overriding these files with custom access roles or expressions.
All data generated by the Wiki is stored as Business Objects in the ENOVIA database.
All objects created by the Wiki component are saved in a separate vault called "TVC Wiki"
Command for showing the TVC Wiki. Can either be added globally in the toolbar or in context of an object type (type menu or as TVC tab).
Attribute holding the Wiki markup for either a page or a comment.
Attribute holding the markup for a page converted to plain text. This is only used for searching Wiki pages.
Attribute holding the "name" of the Wiki page
Holder for all pages in a specific Wiki. If the Wiki is global the Wiki Space is not connected to any object. If the Wiki is in a context the Wiki Space is connected to an ENOVIA object instance.
Represents a wiki page and its information.
Holds all the attachments for a Wiki page. Uses CDM (Common Document Model) to store all files and file versions.
Represents a comment made to a Wiki page.
Relationship used to connect a Wiki Page to its Wiki Space.
Relationship used to connect a Wiki Page to its Wiki Page Attachments object.
Relationship used to connect a Wiki Page Comment to a Wiki Page.
Relationship used to connect a TVC Wiki Space to its context (ENOVIA object instance).
Relationship used to connect a Wiki Page to its parent Wiki Page making it a "Sub Page".
Relationship used to connect Reference Objects to a Wiki Page
Policy for Wiki Pages
Policy for Wiki Page Attachments
Policy for Wiki Page Comments
Policy for Wiki Space
Each Wiki contains a menu that is placed on the left side of the Wiki. This menu dynamically loads all the pages in the current wiki and renders them in a tree layout for navigation. The "Main" page will not be shown in this menu.
This menu will NOT be automatically updated when a new page is created but you can force a menu update by clicking on the menu header.
At the top of the Wiki a breadcrumb is rendered giving the user the ability to see and navigate to previously visited pages. The breadcrumb is showing the history for the current user in the current Wiki. The "home" button rendered to the left points to the current Wiki’s main page.
Below the breadcrumbs and the current wiki page name a number of TVC Tabs is rendered. These tabs allows you to view the content, attachments, history, reference objects and administration for the current Wiki page. The tabs is configured through TVC XML Configurations (tvc:menu:wiki/tabs/WikiContentTabs.xml)
There is two ways of creating a new wiki page.
Create a new page connected to an existing page (Create Page)
Create a "Missing Page" (Create Missing Page)
The page created must be given a unique name that is not used by another page in the current Wiki. When a page is created it will be "blank" and have no content.
If you want to create a new Wiki page this is done in the context of an existing page and the command is located in the top right corner of the current wiki page content. The page will be created and added as a sub page to the page you are currently at.
Clicking this command will allow you to enter a page name and create that page.
If you click on a link to a Wiki page and that page is missing in the current wiki you will be given the ability to quickly create that page by clicking on the create link.
If you want to edit an existing page in the Wiki or a page you just created you can do this by clicking the "Edit" button located in the top right corner of the page.
This will give you two new TVC tabs allowing you to choose between the Rich Text editor and the Markup editor.
The Rich Text editor is a "what-you-see-is-what-you-get" editor that allows you to edit the page content in the exact same way it appears when viewing the page. The editor has a toolbar in the top that gives you all the actions needed to edit the content and insert new content. Some commands are also available on right click.
Rich Text editor buttons described in order:
Bold text
Italic text
Underlined text
Strikethrough text
Add text formatting
Insert unordered list
Insert ordered list
Insert new table
Insert link to an ENOVIA object instance
Insert link to a page Reference Object
Create link (page or url) for selected text
Remove link for selected text
Insert image from page attachments
Add color styling to selected text
Undo last
Redo last
Clear formatting
Print page
Save page
The markup editor allows you to see and edit the page markup. The editor has a toolbar in the top that gives you all the actions needed to insert markup instead of typing it yourself.
Markup editor buttons described in order:
Make selected text "Header 1"
Make selected text "Header 2"
Make selected text "Header 3"
Make selected text "Header 4"
Make selected text "Header 5"
Bold text
Italic text
Strikethrough text
Insert unordered list
Insert ordered list
Insert link to an ENOVIA object instance
Insert image from page attachments
Insert page link
Insert url
Insert new table
Preview changes
Save page
A Wiki page can have any number of comments to it added by the users. These comments are shown at the bottom of each page.
All comments to a Wiki page are shown in the bottom of the page content. If a user has a primary image uploaded it will be shown together with the user name. If a primary image is missing it will use a default image. Comments can be made with the Rich Text editor or with the Markup editor and has the exact same styling abilities as a wiki page.
As a user you can create a comment to a Wiki page by first clicking on the "Comment" command in the top right corner of the Wiki page.
Clicking this command will take you to the bottom of the page showing any previous comments. If you want to add a new comment you click on the "Add comment" link.
You have the ability to add the comment using either the Rich Text editor or the Markup editor in the same way as when editing a Wiki page (see 4.2.4 for more information).
From the Wiki page attachments tab you can upload attachments to the page. Image attachments can then be inserted in to the Wiki page from one of the editors. All attachments can also be downloaded from this page. If you have TVC File Manager installed you will also see the field for drag n drop upload.
On the Wiki page history tab you can see all versions of this page. A new version of the page is created each time a user makes an edit. In the table you can see all versions, when they were created and by who. The "view" columns allow you to see the content of a specific version, either as Rich Text or as markup.
If you also have the TVC Structure Browser component installed in your system you are able to use the "Reference Objects" tab. This tab gives you the ability to use a TVC Search to find any ENOVIA object in the system and connect that to the current wiki page. You can then very easily refer to these objects with links inside your page content.
If you also have the TVC Structure Browser component installed in your system you are able to use the "Administrate" tab. From this tab you can do some various administrative tasks like deleting, removing and adding pages/comments.
In the top right corner of the Wiki you have a free text search field. This allows the user to make a free text search that searches all pages in the current Wiki. The search is configured to check both page names and page content. In order to get a search result you have to enter at least three letters in the search box and you will then be presented a list of matching pages. Each time you enter another letter a new result will be shown. This search is currently using ENOVIA queries to fetch the search result.
The TVC Wiki uses the same markup language as MediaWiki (software used in Wikipedia and other wikis). The complete MediaWiki markup language is currently not supported (only the basics) and there is also some extra markup added that is unique to the TVC Wiki.
| Description | You type | You get |
|---|---|---|
Italic text |
|
italic |
Bold text |
|
bold |
Bold and italic |
|
*bold & italic * |
Underlined |
|
under |
Strike |
or
|
text |
Headings of different levels |
|
Level 1 Level 2 Level 3 Level 4 Level 5 |
Bullet list |
|
|
Numbered list |
|
|
Internal link |
|
Main Page |
Piped internal link |
|
sometext |
External link |
|
|
External link with different label |
|
Technia |
ENOVIA object link |
|
10001 |
Image |
|
|
Image with width |
|
|
Table with headers |
|
a table with two columns and one row |
Tabs are generally used to split content into multiple different pages, which the user easily can switch between, to increase usability. TVC Core contains a feature that allows defining such a tabbed page in a variety of ways.
For an example of how a tabbed page could look like; see the screenshot below:

The tabbed page is very configurable and the features are summarized below:
The tabs can be driven by a menu (stored inside the database, or defined as an XML resource), where each item in the menu will appear as a tab in the user interface.
If the item in the menu is a "sub-menu" that will in turn result in a "nested" tabbed page to be displayed.
If you launch the tabbed page in the context of a business-object (the objectId parameter is passed), then you can choose to either point out a menu explicitly; or you can create a file where you map a business-type to a certain menu.
You can through request parameters define a custom JSP page that will render some information above the actual tabs
Access rights according to the commands/menus defined in the menu will be considered, when the tabs are generated
The last visited tab will be remembered by default
The user can personalize a tab page, by re-arranging tabs and hiding tabs.
Tabs that don’t fit on the row will automatically be "dropped" meaning they get hidden and can only be accessible from the tab configuration drop down menu. This is to prevent the tabs from taking up a lot of space when browser resolution or window is small.
It is also possible to build a tabbed page GUI manually in a JSP page, by using the JSP tags provided by TVC core.
This allows you to create a more complex user interface, for example generating the tabs dynamically, provide custom content above the tabs or even define multiple tab-sections on the same page.
All the details on how to build tabbed-pages are explained within the "TVC Developer Documentation".
To disable the feature of remembering the last visited tab, you can either do so globally or per each tab-page instance:
<init-param>
<param-name>tvc.core.gui.tabPage.rememberSelection</param-name>
<param-value>true | false</param-value>
</init-param>
Or through the request parameter:
rememberSelectedTab=true | false
To disable the possibility to close a tab, this can be done globally:
<init-param>
<param-name>tvc.core.gui.tabPage.enableCloseButton</param-name>
<param-value>true | false</param-value>
</init-param>
and locally (default is false):
<Command>
...
<Fixed>true</Fixed>
</Command>
To disable the possibility to personalize the order/visibility of a tab-page, this can be done globally:
<init-param>
<param-name>tvc.core.gui.tabPage.enableTabCfg</param-name>
<param-value>true | false</param-value>
</init-param>
| If the tab configuration has been disabled, the close button will also be disabled. Otherwise the user won’t have a chance to re-open a closed tab. |
To disable the "tab drop" functionality that hides tabs that doesn’t fit on the row, this can be done globally:
<init-param>
<param-name>tvc.core.gui.tabPage.enableTabDrop</param-name>
<param-value>true | false</param-value>
</init-param>
| If the tab configuration has been disabled, the tab drop functionality will also be disabled. Otherwise the user won’t have a chance to open "dropped" tabs. |
Individual tabs can be styled using a custom theme. Use the "style" setting to add custom class to a tab. Read more on custom themes in chapter 9.

Example:
<Command>
<Label>...</Label>
<URL action="...">
<Param name="..." value="..." />
</URL>
<Fixed>false</Fixed>
<Setting name="class" value="test" />
</Command>
To improve perceived performance and raise acceptance when working with tabs the tab content can be cached and even pre-loaded. This way the tab content is instantly shown when tab is clicked. To reload a cached tab simple click the tab once more when already active.
To enable single tab cache behaviour use the cacheBehavior setting
<Command>
...
<Setting name="cacheBehavior">disabled | cache | preload</Setting>
</Command>
To control global tab cache behaviour use the tvc.core.gui.tabPage.cacheBehavior init-param
<init-param>
<param-name>tvc.core.gui.tabPage.cacheBehavior</param-name>
<param-value>disabled | cache | preload</param-value>
</init-param>
To provide tabs which are initially hidden, one can use the following settings or init-param. Once the tab is added through tab configuration, it will be saved in dataobject.
To enable single tab initially hidden behaviour use the visible setting
<Command>
...
<Setting name="visible">true | false</Setting>
</Command>
To control global tab initially hidden behaviour use the tvc.core.gui.tabPage.visible init-param
<init-param>
<param-name>tvc.core.gui.tabpage.visible</param-name>
<param-value>true | false</param-value>
</init-param>
As of release 2010.2, a new feature called Top Panel was added.
The Top Panel is used to display a configurable frame at the top a tabbed pages definition. The content of the top panel is configured through an XML file.
The screenshot below shows a top panel example, and a short description of the areas within the top panel and what they are called.

The top panel defines/contains the following areas:
Title Form (Shown when the top panel is minimized).
Control(s)
One control can link to a so called top-panel form.
A control can be used to link other pages using a HREF.
A form contains:
Section(s) where each section can have a number of Fields
A form can be switched between view and edit mode.
Tab Menu (name of a menu)
Below the top-panel, a tabbed page is shown.
To use the top-panel create a command that has the HREF property set to call the action "loadTopPanel" and pass the name your top-panel configuration through the parameter "panel". See example below:
${ROOT_DIR}/tvc-action/loadTopPanel?panel=tvc:toppanel/Panel.xml
The top panel definition is stored in a directory called "toppanel" among the XML resources (somewhere under /WEB-INF/tvc in your application directory).
If you omit the domain in the resource name, the location of the top panel definition is:
/WEB-INF/tvc/toppanel
If the top panel definition is stored in a domain, for example acme (tvc:toppanel:acme/Panel.xml) then the resource location is:
/WEB-INF/tvc/acme/toppanel
You define your top panel in XML. The root element must be <TopPanel>. Below you find child element definitions.
| Element Name | Description | Example |
|---|---|---|
Controls |
Container element to FormControl and Control |
- |
TabMenu |
Carries the tab menu definition |
<TabMenu>tvc:menu/tabs/TabMenu.xml</TabMenu> |
Title |
Defines the Form to carry the title definition |
<Form>tvc:toppanelform/Title.xml</Form> |
| Element Name | Description | Example |
|---|---|---|
Form |
Defines the Form xml definition |
<Form>tvc:toppanelform/Form.xml</Form> |
Icon |
Points out the icon for the control. Use either |
<Icon>${COMMON_DIR}/images/iconSmallDescription.gif</Icon> |
IconClass |
Defines the CSS class(es) for the font icon for the control. Font awesome is included by default. Use either |
<IconClass>fa fa-tags</IconClass> |
Label |
Carries the tooltip definition for the control |
<Label>View/EditDetails</Label> |
Access |
Defines access rules for the control. |
|
| Element Name | Description | Example |
|---|---|---|
Height |
Defines a specific height for the control |
<Height>300</Height> |
Href |
Defines a href to display in the control |
<Href>${COMMON_DIR}/emxLifecycle.jsp</Href> |
Icon |
Points out the icon for the control. Use either |
<Icon>${COMMON_DIR}/iconStatus.gif</Icon> |
IconClass |
Defines the CSS class(es) for the font icon for the control. Font awesome is included by default. Use either |
<IconClass>fa fa-tags</IconClass> |
Label |
Carries the tooltip definition for the control |
<Label>Lifecycle</Label> |
Popup |
Defines that the control should open in a popup window. |
<Popup width="800" height="600"/> |
Access |
Defines access rules for the section. |
|
You define your top panel form in XML. The root element must be <Form>.
Below you find child element definitions.
| Element Name | Description | Example |
|---|---|---|
Section |
Container element for Filed elements. Defines the horizontal field sections in a form |
- |
| Element Name | Description | Example |
|---|---|---|
Field |
Defines a form field |
- |
Separator |
Defines a field that acts as a "separator" in the section. |
<Separator/> |
Access |
Defines access rules for the section. |
|
| Element Name | Description | Example |
|---|---|---|
DataHandler |
Point out a class used to retrieve more complex data from
matrix. The class must implement the interface
|
|
Editable |
Defines if the field should be editable or not |
|
Expression |
Defines an mql expression of the data to retrieve from matrix |
|
FieldCellRenderer |
Used to specify alternative rendering for the field.
The class must implement the interface
|
|
Label |
Defines the field label |
|
RangeHandler |
Defines a range handler class that must implement
|
- |
Settings |
Container element for settings |
- |
Access |
Defines access rules for the section. |
|
AutoCompleteHandler |
An autocomplete handler type:
See Autocomplete chapter for more details. |
|
AutoCompleteSettings |
Settings for autocomplete. Should it be case sensitive, what types to choose from, limits, which dataset to use and other. The settings varies for each kind of autocomplete handler. See Autocomplete chapter for more details. |
|
| Element Name | Description | Example |
|---|---|---|
Columns |
Used with InputType textarea to define columns |
|
InputType |
Specifies the type of input |
|
InputWidth |
Defines the width of the input |
|
Required |
Defines if an editable field should be required or not |
|
Rows |
Used with InputType textarea to define rows |
|
Setting |
Define custom settings |
|
SortRangeValues |
Defines if to sort range values |
|
SearchConfig |
Connect a search to a field |
|
RegisteredSuite |
Defines the registered suite. This can be used for localization of labels, where the value of the key is stored in a particular suite string resource file. |
|
Separator |
Only valid on a field in a Top panel title. Defines text to be put at the right hand side of a field, used for separating multiple fields. If you specify an empty Separator element then one space will be used. Values starting and ending with a single quote or double quote will be un-quoted, in order to be able to specify space characters. |
|
MaxLength |
Specifies the max length of an editable input field. |
|
MaxRows |
Specifies the max nr of rows to display of the text. |
|
ValueIfEmpty |
Specifies the value to be used if the actual value is an empty string. By default, the " " replacement is used. |
|
BadChars |
Specifies characters that are treated as "bad" and if the value contains any such character, the user will not be able to modify the value. |
|
ValidationJavaScript |
Can be used to declare custom validation JavaScript code that is inserted on the page that displays this form. |
|
LinkedWith |
Can be used if other fields are updated in the background. On a Refresh these fields will be updated as well. Format: COLUMN:FIELD Separate multiple fields using a comma. |
|
UseTransactionOnEdit |
Can be used to get an update-transaction surrounding the modification of the field. Default is FALSE. |
|
The fields can take advantage of auto-completion. If you have a field that applies to "type" and is editable, the way to configure such field to take advantage of auto complete is slightly different. See example below:
<Field>
<Label>Type:</Label>
<Expression><![CDATA[$<type>]]></Expression>
<Editable />
<AutoCompleteHandler>type</AutoCompleteHandler>
<AutoCompleteSettings>{
'handler' : {
'rootTypes' : ['type_HardwarePart', 'type_SoftwarePart']
}
}</AutoCompleteSettings>
</Field>
E.g. you use the setting "Type" to specify the "root" type for the object.
If you want to enable auto completion for users, then you can enable that through the following configuration:
<Field>
<Label>Owner:</Label>
<Editable />
<Expression><![CDATA[$<owner>]]></Expression>
<DataHandler>com.technia.tvc.core.gui.toppanel.form.builtin.UserNameHandler</DataHandler>
<AutoCompleteHandler>user</AutoCompletHandler>
</Field>
Settings are configured in JSON format in the AutoCompleteSettings element.
Example setting limit to 50, case sensitive, disable localization and only matching values starting with the searched value:
<AutoCompleteSettings>{
'handler' : {
'limit' : 50,
'caseSensitive' : false,
'localize' : false,
'contains' : false
}
}</AutoCompleteSettings>
See the Autocomplete chapter for more details.
Both on control, section level as well as per field level, one can restrict access to the control/section/field.
The access restriction can be defined based upon following:
Role Assignment
Group Assignment
Person (A named user)
Access Mask (Access mask for the current object)
Access Program (A JPO that evaluates the access rights)
The example below illustrates how you can construct the access restriction:
<Field> <!-- Or Section -->
<Access>
<Role>role_FirstRole</Role>
<Role>role_SecondRole</Role>
<Group>group_SomeGroup</Group>
<Mask>modify,checkout</Mask>
</Access>
</Field>
Or use an access program:
<Field> <!-- Or Section -->
<Access>
<Program name="MyJPO" method="checkAccess"/>
</Access>
</Field>
This datahandler can be used for modifying related objects, e.g connecting and disconnecting them.
<Field>
<Label>Design Organization:</Label>
<Editable />
<DataHandler>com.technia.tvc.core.gui.toppanel.form.builtin.RelatedObjectHandler</DataHandler>
<AutoCompleteHandler>organization</AutoCompleteHandler>
<Settings>
<Setting name="Relationship">relationship_DesignResponsibility</Setting>
<Setting name="Direction">to</Setting>
<Setting name="Display Property">name</Setting>
<Setting name="OpenInPopup">true</Setting>
</Settings>
</Field>
| Setting | Description | Example |
|---|---|---|
Relationship |
The symbolic name of the relationship to use. |
relationship_DesignResponsibility |
Direction |
The direction of the connection |
|
Display Property |
What to select and display from the connected object(s) |
Name |
OpenInPopup |
Optional parameter to determine the link target. True (default) means that the related object is opened in a new popup window. False means that the link opens in the same parent window. |
|
This datahandler is used for handling user names. Auto-completion can be configured as well.
<Field>
<Label>Owner:</Label>
<Editable />
<Expression><![CDATA[$<owner>]]></Expression>
<DataHandler>com.technia.tvc.core.gui.toppanel.form.builtin.UserNameHandler</DataHandler>
<AutoCompleteHandler>user</AutoCompleteHandler>
</Field>
Examples
<TopPanel>
<Title>
<Form>tvc:toppanelform/Title.xml</Form>
</Title>
<Controls>
<FormControl>
<Label>View/Edit Details</Label>
<Icon>${COMMON_DIR}/images/iconSmallDescription.gif</Icon>
<Form>tvc:toppanelform/Form.xml</Form>
</FormControl>
<Control>
<Label>Lifecycle</Label>
<Icon>${COMMON_DIR}/images/iconStatus.gif</Icon>
<Href>${COMMON_DIR}/emxLifecycle.jsp</Href>
</Control>
</Controls>
<TabMenu>tvc:menu/tabs/TabMenu.xml</TabMenu>
</TopPanel>
<Form>
<Section>
<Field>
<Expression><![CDATA[$<type>]]></Expression>
</Field>
<Field>
<Expression><![CDATA[$<attribute[attribute_Title]>]]></Expression>
<Settings>
<Separator>: </Separator>
</Settings>
</Field>
</Section>
</Form>
<Form>
<Section>
<Field>
<Label>Style #:</Label>
<Expression><![CDATA[$<attribute[attribute_StyleNumber].value>
]]></Expression>
<Editable />
<Settings>
<InputType>textbox</InputType>
<InputWidth>120</InputWidth>
<Required>true</Required>
</Settings>
</Field>
<Field>
<Label>Selected Sizes:</Label>
<Expression>dummy</Expression>
<RegisteredSuite>ApparelAccelerator</RegisteredSuite>
<DataHandler>com.technia.acme.SelectedSizesDataHandler</DataHandler>
</Field>
<Field>
<Label></Label>
<RegisteredSuite>ApparelAccelerator</RegisteredSuite>
</Field>
<Field>
<Label>Comments:</Label>
<Expression><![CDATA[$<attribute[attribute_Comment]>]]></Expression>
<Editable />
<Settings>
<InputType>textarea</InputType>
<Columns>25</Columns>
<Rows>2</Rows>
<Setting name="Text Length">200</Setting>
</Settings>
</Field>
</Section>
<Section>
<Field>
<Label>Marketing Name:</Label>
<Expression><![CDATA[$<attribute[attribute_MarketingName].value>]]></Expression>
<Editable />
<Settings>
<InputType>textbox</InputType>
<InputWidth>120</InputWidth>
<Required>true</Required>
</Settings>
</Field>
</Section>
<Section>
<Field>
<Label>Season:</Label>
<Expression><![CDATA[$<to[relationship_ProductMeasurement].from.revision>]]></Expression>
<Settings>
<InputType>textbox</InputType>
<InputWidth>120</InputWidth>
<Required>true</Required>
</Settings>
</Field>
<Field>
<Label>M-Chart Revision:</Label>
<Expression><![CDATA[$<revision>]]></Expression>
<Settings>
<InputType>textbox</InputType>
<InputWidth>120</InputWidth>
<Required>true</Required>
</Settings>
</Field>
</Section>
<Section>
<Field>
<Label>Supplier:</Label>
<Expression><![CDATA[$<to[relationship_ProductMeasurement].from.to[relationship_ManufacturingResponsibility].from.name>]]></Expression>
<Settings>
<InputType>textbox</InputType>
<InputWidth>120</InputWidth>
<Required>true</Required>
</Settings>
</Field>
<Field>
<Label>Copied From:</Label>
<Expression>dummy</Expression>
<DataHandler>com.technia.acme.datahandler.CopiedFromDataHandler</DataHandler>
<FieldCellRenderer>com.technia.acme.render.toppanel.CopiedFromRenderer</FieldCellRenderer>
<Settings>
<InputType>textbox</InputType>
<InputWidth>120</InputWidth>
<Required>true</Required>
</Settings>
</Field>
</Section>
<Section>
<Field>
<Label>State:</Label>
<Expression><![CDATA[$<current>]]></Expression>
<Settings>
<InputType>textbox</InputType>
<InputWidth>120</InputWidth>
<Required>true</Required>
</Settings>
</Field>
<Field>
<Label>Template Revision:</Label>
<Expression><![CDATA[$<from.revision>]]></Expression>
<Settings>
<InputType>textbox</InputType>
<InputWidth>120</InputWidth>
<Required>true</Required>
</Settings>
</Field>
</Section>
</Form>
As of release 2012.3, a new feature called "Image Manager" was added. This functionality adds a number of tools allowing the user to upload, browse and edit images uploaded to any Enovia object.
The complete Image Manager can be added with the command called "TVC Image Manager" or with the following href.
${ROOT_DIR}/tvc-action/menuBasedTabPage/foo.jsp?menu=tvc:menu:core:imagemanager/ImageManagerTabs.xml
This will add the three tabs "Upload", "Browse" and "Edit".
You can also use each part of the Image Manager separately, see next chapter.
| If any of the image manager actions is launched outside of an Enovia object context you need to pass the objectId parameter. |
The Image Manager consists of a number of different parts, each can be used individually with its corresponding TVC action.
The upload page can be launched with the following action.
${ROOT_DIR}/tvc-action/imageManagerUpload
This will launch a page that allows you to upload new images to the object you are in context of. Any previously uploaded images will also be displayed.

If you have the TVC File Manager installed this page will include a drop zone allowing you to drag and drop files from your computer (Note: This does not use the standard applet based drop zone from the TVC file manager so it cannot be configured with drop zone handlers etc.) Since this drop zone is html5 based it will only work in browsers that supports this, see Browser Requirements below for more information.
There is also a button allowing you to open a standard file browser to select images from your computer.
The images will be uploaded to a connected "Image Holder" object, see section 6.2 (Images and annotations data model) for more information.
The image browsing page can be launched with the following action.
${ROOT_DIR}/tvc-action/imageManagerSlideShow
This will launch a "gallery" with thumbnails of all the images currently uploaded to the object. This gallery allows you to browse/view all images in various ways.

There are a number of request parameters you can use to configure the gallery when launching this action. NOTE: All string values needs to be inside apostrophes.
| Parameter Name | Description | Default | Values |
|---|---|---|---|
transition |
Defines what transition to use when browsing to the next/previous image. |
‘fade’ |
‘fade’, ‘flash’, ‘pulse’, ‘slide’, ‘fadeslide’ |
responsive |
Sets if gallery should be responsive to browser window size or not. |
true |
true, false |
imageCrop |
Defines how the main image will be cropped inside its container. By default all images will be scaled to fill the stage, centered and cropped. |
true |
true, false, ‘height’, ‘width’, ‘landscape’, ‘portrait’ |
maxScaleRatio |
Defines how much an image can be scaled. |
3 |
Any number |
height |
Sets the gallery height, either fixed or relative. The default value 0.5625 will set a 16/9 ratio. Setting it to 400 will set the height to 400 pixels. |
0.5625 |
Any number |
width |
Sets the gallery width. By default the width will be fetched from the containing element. You can use a number to set it to a fixed width. |
‘auto’ |
‘auto’ or any number |
showCounter |
Toggles the counter. |
true |
true, false |
lightbox |
Attach a lightbox (to zoom in) when users clicks an image. |
true |
true, false |
| This gallery also works on most new smart phones and tablets. If used from TVC mobile it needs to be launched into a new browser tab. Se TVX for an example. |
The image editing page can be launched with the following action.
${ROOT_DIR}/tvc-action/imageManagerEdit
This will launch a page displaying all uploaded images with a menu containing some image editing commands.

The "Set as primary" command will set the selected image as "primary".
The "Delete Image" command will delete the selected image.
The "Annotate" command will launch the image annotation page for the selected image. See next chapter for more detailed information about this.
The image annotation page can be loaded directly for an image with the following action.
${ROOT_DIR}/tvc-action/imageManagerAnnotate
This action needs the following parameters when loaded
| Parameter Name | Description |
|---|---|
objectId |
Enovia Object ID for the object containing the image |
imageName |
File name of the image to annotate. (Object can contain multiple images) |
This will launch the image together with a toolbar of commands that allows you to annotate the image with text and different shapes. The annotation will be saved in the database (both annotation data and as a flattened image) so you can load an existing annotation for later editing/viewing. For detailed information on how the annotations are saved, see the chapter: Images and annotations data model.

| The annotation also page works on most new smart phones and tablets. If used from TVC mobile it needs to be launched into a new browser tab. Se TVX for an example. |
The Image Browsing and Image Editing pages can be loaded with images from several objects at the same time. You can do this in two different ways, either by sending several object ids as request parameters or by using a related object expression to load the other objects.
| Parameters | Example | Description |
|---|---|---|
objectId |
|
Will load images from all objects passed as request parameters. |
relatedImageExpression |
|
Will use the expression to find objects to load images for. |
The TVC Image Manager uses the Enovia data model for uploading images to a related object of the type "Image Holder". Each image that is uploaded will be checked in to this related object together with several resized smaller versions of the image.
If one of these images is annotated and saved an object of the type "TVC Image Annotation" will be connected to the Image holder. This is connected with the relationship "TVC Image Annotation" containing an attribute "TVC Annotated Image" that specifies the name of the annotated image. The annotation object will have an attribute containing the annotation data so it can be loaded and edited again. It will also contain a checked in file that is a flattened jpg of the annotated image for use in reports and other places.
So the image original that is being annotated will be kept unchanged and not modified.
By default the annotated image is displayed in view annotation mode only. To preview annotation in upload, browse and edit tabs of Image Manager following tvc property setting has to be configured.
tvc.core.imageManager.previewAnnotation=true
URL parameter previewAnnotation=false can be passed in "Image Upload", "Image Browse" and "Image Editing" tabs if preview annotation is not required in any of them.
URL parameter previewAnnotation’s default value is true and it is obeyed only when global annotation property setting is enabled.
The different parts of the TVC Image manager is based on several different HTML5 components. Because of this there are some requirements on browser type/version as well as Enovia version (if using an older version).
Internet Explorer 9 is supported for everything except the drop zone that will be hidden (will probably work in later versions of IE). Also note that Image Manager only works if IE9 is used together with Enovia 2013 or newer. This is due to how Enovia is rendered in the browser. One workaround to get it to work in older Enovia versions with IE9 is to launch the Image Manager in a popup window. Any version below IE 9 is not supported.
The image manager is tested and works with several of the newer versions of Firefox, Chrome and Safari. We don’t have a complete list of supported versions for these browsers but if you have any issues please report those and we should be able to fix that. There is no special requirement on the Enovia version if using one of these browsers.
As of release 2010.2, a new feature called Image Flow was added.
The Image Flow allows the user to browse through a set of images. The images are typically the primary images associated to a set of objects, but it is possible to launch the image flow and show all images associated to an object.
Moreover, the image flow can be configured to launch an URL below the image. When the image is shown, the object associated with the image will be passed along to the specified URL and the page is loaded.
The example screenshot below illustrates an example use case of an image flow.

The image flow is configured via an XML file, and to launch the image flow you should use the URL below:
${ROOT_DIR}/tvc-action/imageflow?config=tvc:imageflow/MyImageFlow.xml
The config parameter can be omitted, in that case the image flow will only display the images associated with the object provided in the request. However, typically is that you use a configuration for the image flow. The sub chapter describes the configuration in detail.
The Image Flow component is configured via an XML resource. The XML configuration is of type "imageflow" hence it must be stored inside a directory under the WEB-INF/tvc folder called "imageflow". If you use namespaces (domains), the folder is slightly different.
<ImageFlow>(1)
<Height>50%</Height>(2)
<Images>(3)
<ImageFormat>large</ImageFormat>(4)
<TitlePattern>$<attribute[attribute_MarketingName]></TitlePattern>(5)
<Loader>(6)
<Query type="type_Model" vault="vault_eServiceProduction"/>
</Loader>
</Images>
<View>
<URL action="navigate">(7)
<Param name="pageConfig">tvc:pageconfig:tvx:vcc/Products.xml</Param>
<Param name="inquiry">tvc:inquiry:tvx:vcc/ProductsFromModel.xml</Param>
<Param name="portalMode">true</Param>
</URL>
</View>
</ImageFlow>
| 1 | The root tag is always <ImageFlow>. |
| 2 | The <Height> tag specifies the height of the Image Flow itself; you can
either use percentage or pixels. |
| 3 | Within the <Images> element you configure what’s displayed in the Image
Flow component. |
| 4 | The <ImageFormat> designates which format to use. The accepted values
are ‘thumbnail’, ‘small’, ‘medium’ and ‘large’. |
| 5 | The <TitlePattern> element defines a pattern that will be evaluated to
extract the title to use for each object/image. You’re allowed to use
business object select macros within this pattern to get data from each
object. |
| 6 | The <Loader> element configures how to find the objects whose images
will be displayed in the Image Flow. Apart from <Query/>, you can also
use <Expansion type=’’ relationship=’’ from=’*’ />, <Inquiry
inquiry=’’ /> and <JPO program=’’ function=’’ /> within this element.
See next chapter for further details. |
| 7 | Lastly, the <URL> element defines which URL to be used below the Image
Flow. |
The data can be loaded using a couple of different alternatives:
Expansion
Query
Inquiry
JPO
Data Set
To use an expansion, the image flow must be launched in the context of an object, while the latter doesn’t require so.
The example below shows the attributes that you can use to control a query
<Query type="type_Part,type_AnotherType"
name="A*"
revision="*"
vault="vault_eServiceProduction"
where=""
owner=""
limit="1000"
expand="true"/>
The example below shows the attributes that you can use to control an expansion.
<Expansion type="type_Part,type_AnotherType"
relationship="relationship_EBOM,relationship_AnotherRel"
objectWhere=""
relationshipWhere=""
recurseToLevel="2"
from="true"
to="false" />
The example below shows the attributes that you can use to control an inquiry.
<Inquiry inquiry="name of inquiry"/>
The images that are taken from the objects loaded are either the Image connected with the "Primary Image" relationship, or the primary image specified on the "Image Holder" object connected. E.g. the image flow supports the two different alternate image concepts that exist in the ENOVIA Centrals.
You can also use a custom so called Image finder, which evaluates what images to be included.
To do so, you need to specify the following within the configuration:
<ImageFlow>
<Images>
<Finder>value</Finder>
The value can either be "primary", "objectimage" or a class name of a class that implements the interface shown below:
package com.technia.tvc.core.gui.imageflow.model.finder;
import com.technia.tvc.core.gui.imageflow.model.Image;
import com.technia.tvc.core.TVCException;
import com.technia.tvc.core.db.aef.env.Environment;
public interface ImageFinder {
Image[] getImages(Environment env) throws TVCException;
}
If omitting the finder from the definition, the primary images are loaded (same as saying "primary"). If you instead want to load all images available from the object(s) loaded, then you use the "objectimage" string instead.
And as mentioned, if you need to load the images in a custom way, implement your own ImageFinder.
It is possible to create charts that are predefined with an XML configuration file. The chart is then accessed from an ordinary command, which contains the reference to the XML file that defines/configures the chart.
The chart is based upon data based upon applying a system table (or XML table) upon objects/connections loaded via an inquiry, JPO or through another mechanism.
To create a Command that displays the chart you set the Href parameter as shown below. The TVC action is named "chart" and takes one parameter, "chartConfig". The value of "chartConfig" should be the name of the xml file defining the chart.
Example:
${ROOT_DIR}/tvc-action/chart?chartConfig=<name of configuration>

The example below illustrates how to define a chart with xml.
<Chart>
<ChartType>BAR</ChartType>
<Columns>
<Column>Name</Column>
<Column>Weight</Column>
</Columns>
<DataProvider>inquiry:tvc:inquiry:tvx:enc/Heaviest10Parts.xml</DataProvider>
<TableName>tvc:table:tvx:enc/PartInfo.xml</TableName>
<Title>Default title</Title>
<Title locale="sv_SE">Localized title</Title>
<XaxisTitle>Default x-axis title</XaxisTitle>
<XaxisTitle locale="sv_SE">Localized x-axis title</XaxisTitle>
<YaxisTitle>Default y-axis title</YaxisTitle>
<YaxisTitle locale="sv_SE">Localized y-axis title</YaxisTitle>
<Width>800</Width>
<Height>400</Height>
<Render3D>false</Render3D>
<ShowLegend>false</ShowLegend>
<ShowPercent>false</ShowPercent>
<ShowNumberLabel>true</ShowNumberLabel>
<ShowNameLabel>true</ShowNameLabel>
<CountOccurrences>false</CountOccurrences>
<BaseColor>rgb(55, 85, 15)</BaseColor>
<ChartColors>
<Color>rgb(76, 164, 173)</Color>
<Color>rgb(131, 224, 235)</Color>
<Color>rgb(123, 143, 186)</Color>
<Color>rgb(83, 99, 150)</Color>
<Color>rgb(91, 56, 140)</Color>
</ChartColors>
</Chart>
| Element Name | Description | Mandatory | Values |
|---|---|---|---|
ChartType |
The type of chart to be displayed |
Yes |
See below |
Columns |
List of column names with one or more "<Column>" elements. |
Yes |
Any names that is available in the custom java class or in the Structure Browser if the chart is created from a structure browser. |
DataProvider |
The data provider. More about data providers. |
Yes |
See below |
TableName |
Name of the table to apply on the data from the Inquiry. |
Yes, if an Inquiry is used. |
Table name. |
Title |
The chart title text |
No |
Chart title text. Can be localized using the attribute "locale". |
XaxisTitle |
Title text for the X axis |
No |
X axis title text. Can be localized using the attribute "locale". |
YaxisTitle |
Title text for the Y axis |
No |
Y axis title text. Can be localized using the attribute "locale". |
Width |
Sets the width of the chart. |
No |
Numeric value. Default is 600. |
Height |
Sets the height of the chart. |
No |
Numeric value. Default is 600. |
CountOccurrences |
If set to true the Y axis will show the number of occurrences of each value of the supplied column. If false the Y axis will show each value of the column which then must contain a numerical value. |
No |
True/false. True is default. |
Render3D |
Determines whether the chart is shown in 3D. Exceptions listed in below. |
No |
True/false. False is default. |
ShowLegend |
Determines whether the legend is shown. Exceptions listed in below. |
No |
True/false. False is default. |
ShowPercent |
Determines whether the percent value is shown. Exceptions listed in below. |
No |
True/false. False is default. |
ShowNumberLabel |
Determines whether a label with the value number is shown. Exceptions listed below. |
No |
True/false. False is default. |
ShowNameLabel |
Determines whether a label with the name of the data series is shown. Onlya available for Chart type Bar and Stacked_Bar. |
No |
True/false. False is default. |
BaseColor |
Used to set the base color of the chart. The given color is the darkest used, together with the required number of lighter shades of the same color. If "ChartColors" are supplied, "BaseColor" is not used. |
No |
Text containing an rgb value on the format "rgb(rVal, gVal, bVal)". Default is a shade of blue. |
ChartColors |
List of colors with one or more "<ChartColor>" elements. If not enough colors are in the list, they will be reused. |
No |
Ex: <ChartColor>rgb(45, 65, 185)</ChartColor> |
Here is a brief description of which settings are available for tweaking your charts, per chart type.
ChartType id "PIE".
Needs one column with input data.
Labels are always visible.
"ShowPercent", "ShowLegend" and "Render3D" are available.
ChartType id "MULTIPLE_PIE".
Needs two columns with input data.
Labels are always visible.
"ShowPercent", "ShowLegend" and "Render3D" are available.
ChartType id "RING".
Needs one column with input data.
Labels are always visible.
"ShowPercent" is available.
"Render3D" and "ShowLegend" are unavailable.
ChartType id "BAR"
Needs one or two columns with input data
"Render3D" and "ShowLegend" are available
"ShowPercent" is unavailable
ChartType id "STACKED_BAR"
Needs two columns with input data
"Render3D" and "ShowLegend" are available
"ShowPercent" is unavailable
ChartType id "AREA"
Needs two columns with input data
"ShowLegend" is available
"ShowPercent" and "Render3D" are unavailable
ChartType id "STACKED_AREA"
Needs two columns with input data
"ShowLegend" is available
"ShowPercent" and "Render3D" are unavailable
ChartType id "TIMELINE"
Needs one, two or three columns
Column 1 – must be a date, which is mapped to the X axis.
Column 2 – if "CountOccurrences" is set to true then this will the category column. If "CountOccurrences" is set to false then this column will be used as a numeric value mapped to the Y axis. If two objects have the same date those values will be accumulated.
Column 3 – this is the category column when "CountOccurrences" is set to false.
"ShowLegend" is available
"ShowPercent" and "Render3D" are unavailable
ChartType id "BUBBLE"
Needs four columns with input data and can take one optional fifth column. They are used in top-down order as follows
Column 1 is the x-axis
Column 2 is the y-axis
Column 3 is the size of the bubbles
Column 4 is the color of the bubbles
Column 5 is optional and defines the data for the labels on the bubbles
"ShowPercent" and "Render3D" are unavailable
"ShowLegend" cannot be turned off
The data provider element defines how the data that drives the chart is being loaded. Depending on how the data is being loaded, the format of the data provider value is different. The purpose of a dataloader is to provide the objects (and optionally connections) that is being a part of the chart.
The list below illustrates the different data providers that are supported, and the format:
| Type | Example | Description |
|---|---|---|
Inquiry |
|
Will use the specified inquiry to load the data. |
JPO |
|
Will use the specified JPO/method to load the data. |
Java |
|
Will use a custom data provider, which is implemented in a Java class. The Java class must implement the interface:
This interface has one method that is required to be implemented. That
method returns the data as a |
The default font used in the generated charts is Verdana. To change this font, one can apply the following init-parameter:
<init-param>
<param-name>tvc.core.chart.baseFont</param-name>
<param-value>MS Mincho</param-value>
</init-param>
Note that multi-byte characters might not be rendered correctly when using Java 1.5 or previous versions. To correct this, copy the font files into the JAVA_HOME/jre/lib/fonts directory on the application server.
It is also possible to configure the sizes of the fonts used in the different places.
This is done through init-parameters; listed below:
tvc.core.chart.font.titleFont tvc.core.chart.font.legendFont tvc.core.chart.font.labelFont tvc.core.chart.font.pieTitleFont tvc.core.chart.font.bubbleTitleFont tvc.core.chart.font.bubbleLabelFont tvc.core.chart.font.numberAxisLabelFont tvc.core.chart.font.numberAxisTickLabelFont
The value for these init-parameters should be a value that is accepted by the java.awt.Font.decode(String) method, example: "arial-plain-12".
It’s also possible to configure some colors used;
tvc.core.chart.color.labelBackgroundColor tvc.core.chart.color.labelOutlineColor tvc.core.chart.color.labelLinkColor tvc.core.chart.color.pieTitleColor tvc.core.chart.color.bubbleTitleColor
The values for the colors should be according to this syntax:
RGB: rgb(55,100,99)
HEX: #FFACDA
Named Color: White, LightGray, LightYellow, Indigo, … (the list is too long…)
Another alternative is to modify these upon startup; e.g. in your plugin, add some code within your "init()" method that initializes the look and feel of the generated charts.
Example:
import com.technia.tvc.core.chart.ChartLookAndFeel;
...
public void init() {
ChartLookAndFeel lf = ChartLookAndFeel.getInstance();
lf.setTitleFont(new Font(...));
lf.setLegendFont(new Font(...));
...
}
...
It’s however important that you do this once and not try to change this when the application is up and running, since the chart factory will use the values from the ChartLookAndFeel instance when the charts are being created.
Data sets allows an administrator to define complex data retrievals within XML format. This feature was initially developed for use in the report generator but due to its power and flexibility, the support for using data-sets has increased into most of the TVC Components nowadays.
A data set can either be a structure consisting of objects and connections or a "flat" list of objects (each row in a flat list can also be associated with a connection).
A data set can typically be used to load data in several places across the TVC components. Some examples of use are:
Loading data into a Structure Browser
Loading data into a Grid Browser
Loading data within the image flow
Loading data into a chart / dashboard.
Loading data into a Report
A data set is defined in XML and is stored as a "resource" below the
/WEB-INF/tvc folder within the ENOVIA web-application. The type of
this resource is called "dataset". Below is a table showing some
examples of the paths and their corresponding resource name to a
particular data set.
| File System Path (Relative from the root dir of your application) | Resource Name |
|---|---|
/WEB-INF/tvc/dataset/MyDataSet.xml |
tvc:dataset/MyDataSet.xml |
/WEB-INF/tvc/tvx/enc/dataset/MyDataSet.xml |
tvc:dataset:tvx:enc/MyDataSet.xml |
/WEB-INF/tvc/dataset/test/MyDataSet.xml |
tvc:dataset/test/MyDataSet.xml |
/WEB-INF/tvc/tvx/enc/dataset/test/MyDataSet.xml |
tvc.dataset:tvx:enc/test/MyDataSet.xml |
The root element of the XML data structure is <DataSet>.
Below the root element, you will declare a so called loader.
There exist a number of different loaders, some of them require "input", which either comes from the "caller" such as object-ids provided in request parameters or from a "child" loader, while some loaders doesn’t require input.
The table below describes the built-in loaders together with a short description and reference to the chapter where they are described in more detail.
| Loader | XML Element | Description | Requires Input |
|---|---|---|---|
Expand |
<Expand> |
Performs an expansion. The way the expansion is done, is configured through child elements. |
Yes |
Inquiry |
<Inqiry> |
Executes an inquiry. Either the inquiry is defined "inline" in the XML, or you reference an existing inquiry. |
No |
Query |
<Query> |
Performs a temp query. The query parameters are configured as child elements. |
No |
Java Program Object |
<JPO> |
Executes a Java Program Object. |
No |
Select |
<Select> |
Performs a "select" to retrieve the desired objects. |
Yes |
Flatten |
<Flatten> |
Converts a structure into a flat list. E.g. removes all hierarchy information |
Yes |
End Items |
<EndItems> |
Removes all nodes except the leafs from astructure. |
Yes |
Remove Duplicate Objects |
<RemoveDuplicates> |
Ensures that each object only appears once. |
Yes |
Filter |
<Filter> |
Performs a filtering of the rows based upon an expression. |
Yes |
Java |
<Java> |
Defines a loader implemented in Java |
No |
Source |
<Source> |
Explicitly obtains the objects provided by the client; typically the values either from the "emxTableRowId" parameter or the "objectId" parameter. |
No |
PersonObject |
<PersonObject> |
Gives the object-id of the person object associated with the current user. |
No |
CompanyObject |
<CompanyObject> |
Gives the object-id of the company object associated with the current user. |
No |
RemoveRoots |
<RemoveRoots> |
Removes the root nodes from a structure. |
Yes |
DataSetRef |
<DataSetRef> |
Includes the content from another data-set |
No |
Structure |
<Structure> |
Converts a flat list of objects into a structure, where the root nodes of the structure originate from the rows in the flat list. |
Yes |
Union |
<Union> |
Combines the result from several loaders into one flat list OR one structure. |
Yes |
Intersection |
<Intersection> |
Takes the id’s that are present in all child loaders. |
Yes |
Complement |
<Complement> |
Loads data from one or more child loaders, and exclude data by defining other child loaders that defines what to exclude. |
Yes |
DoPrivileged |
<DoProvileged> |
Runs the child loaders with system privileges |
Yes |
LatestInState |
<LatestInState> |
Finds the latest revision of the object in a particular state. |
Yes |
A loader might require input, while some don’t. The loaders that requires input can either use input from a loader defined as a child element OR it can use the input as provided by the caller (typically from request parameters such as "emxTableRowIdParam" passed from selected rows in a table/structure page OR the "objectId" parameter that also is used to pass the id of one or more objects).
Below is an example how to "nest" the loaders:
<DataSet>
<RemoveDuplicates>(5)
<Filter usesBusinessObject="true">(4)
<Expression>attribute[Unit of Measure] == kg</Expression>
<EndItems>(3)
<Expand>(2)
<Inquiry>(1)
<Name>tvc:inquiry/MyInquiry</Name>
</Inquiry>
</Expand>
</EndItems>
</Filter>
</RemoveDuplicates>
</DataSet>
Note that this example is not complete; some configuration details has been left out for readability purpose.
What this example actually does is:
| 1 | Use an inquiry to load some objects |
| 2 | The objects loaded from the inquiry is expanded according to the Expand definition |
| 3 | All rows except the end items within the structure is removed |
| 4 | A filter is applied to the objects, which will remove all objects that doesn’t fulfil the filter-expression |
| 5 | Finally, all objects appearing more than once are removed. |
This illustrates how to accomplish a quite complex data-retrieval just by using a combination of different loaders. If you would have implemented this code as for example a JPO, you would typically need to implement +100 rows of Java code.
A complete definition how to expand a structure is shown below. Note that some elements are optional.
<DataSet>
<Expand>
<From>true</From>
<To>false</To>
<Depth>1</Depth>
<TypePattern>
<Type>type_Part</Type>
<Type>...</Type>
</TypePattern>
<RelationshipPattern>
<Relationship>relationship_SparePart</Relationship>
<Relationship>...</Relationship>
</RelationshipPattern>
<ObjectWhere>...expression...</ObjectWhere>
<RelWhere>...expression...</RelWhere>
<LoadRootInquiry>name of inquiry that provides the root objects</LoadRootInquiry>
</Expand>
</DataSet>
Setting the depth to 0, you will expand as deep as possible. This can only be done in one direction.
| The "LoadRootInquiry" element can be used to specify an inquiry that loads the root nodes. This would be the same as doing: |
<Expand>
<Inquiry>
<Name>name of inquiry</Name>
</Inquiry>
</Expand>
The difference is that the first approach will execute slightly more efficient.
Executing an inquiry can be done in two different ways. Either you will reference an existing inquiry by its name, or you can define the inquiry inline. Below are two examples illustrating both ways.
<Inquiry>
<Name>name of inquiry to run</Name>
</Inquiry>
Alternatively, you can also say:
<Inquiry name="name of inquiry"/>
Or by defining the inquiry inline:
<Inquiry>
<Code>temp query bus Part * * limit 100</Code>
<Pattern>*|*|*|${OID}</Pattern>
<Format>${OID}</Format>
</Inquiry>
A complete definition how to perform a query is shown below. Note that some elements are optional.
<Query>
<ExpandType>true</ExpandType> <!-- whether or not to find sub-types -->
<FindLimit>0</FindLimit> <!-- the find limit -->
<TypePattern>
<Type>type_Part</Type>
<Type>type_AnotherType</Type>
</TypePattern>
<NamePattern>
<Name>A*</Name>
<Name>B*</Name>
</NamePattern>
<RevisionPattern>
<Revision>A</Revision>
<Revision>B</Revision>
<Revision>C</Revision>
</RevisionPattern>
<OwnerPattern>
<Owner>A user</Owner>
</OwnerPattern>
<VaultPattern>
<Vault>A vault</Vault>
<Vault>Another vault</Vault>
</VaultPattern>
<Where>$<attribute[attribute_Weight]< > 100</Where>
</Query>
The JPO loader can be used to invoke a JPO. The example below illustrates how to configure such loader.
<JPO>
<Name>MyJPO</Name>
<Method>myMethod</Method>
</JPO>
Alternatively, you can also say:
<JPO name="MyJPO" method="myMethod"/>
The JPO method must return a MapList where each Map in the list contains the "id" and optionally the "id[connection]" key.
The select loader selects id’s based upon the input to the select loader. Below is an example how to do so:
<Select>
<Statement>from[Documents].to.revisions.id</Statement>
<Statement>from[Specs].to.revisions.id</Statement>
</Select>
By default, the select loader assumes that you select on business objects, and the select returns other business object id’s. If you select on relationships, or your select clause returns connection id’s, see below for details.
Note 1: In this case, the select is done upon the implicit input objects as provided by the client. You can use a child-loader also; in that case, the select is based upon the objects provided by that loader.
Note 2: it is possible to have several statements. Each statement must of course return object-ids.
If you have select statements that operates on connection id’s; then you can specify so as shown below:
<Select selectFromConnections="true">
<Statement>to.id</Statement>
</Select>
If your select statement would return connection id’s instead of object id’s, then you can specify so as shown below:
<Select selectReturnsConnections="true">
<Statement>to.id</Statement>
</Select>
If you only have one select statement, this can be written as:
<Select statement="from[Documents].to.id"/>
The flatten loader doesn’t have any configuration options. The only requirement is that the input to this loader is a structure; if not, nothing will be done by this loader.
Example:
<Flatten>
<Expand>
...
</Expand>
</Flatten>
The end items loader doesn’t have any configuration options. The only requirement is that the input to this loader is a structure; if not, nothing will be done by this loader.
Example:
<EndItems>
<Expand>
...
</Expand>
</EndItems>
The remove duplicates loader requires input, either a structure or a flat list. In case of a structure, the removal of duplicates is only made on the root-nodes in the structure.
Example:
<RemoveDuplicates>
<EndItems>
<Expand>
...
</Expand>
</EndItems>
</RemoveDuplicates>
If you need to retain occurrences of the same object if the connection id differs, specify so using the attribute "ignoreConnectId" as shown below:
<RemoveDuplicates ignoreConnectId="false">
<EndItems>
<Expand>
...
</Expand>
</EndItems>
</RemoveDuplicates>
The filter loader can be used to filter out objects based upon an expression. This loader requires input. The example below expands a structure, makes it flat, then applies the filter and removes all the rows not matching this filter.
<Filter>
<Expression>$<attribute[attribute_Classification]> == ABC</Expression>
<Flatten>
<Expand>
...
</Expand>
</Flatten>
</Filter>
Alternatively, you can also say:
<Filter expression="$<attribute[attribute_ABC]> == 'DEF'"/>
NOTE 1: The expression is evaluated using the ENOVIA select statement "evaluate[${EXPRESSION}]". All rows returning TRUE will be accepted, others will be filtered out.
NOTE 2: If you need to combine criteria using AND/OR operators; you might in some cases need to use the AND or OR key words instead of using the && and || operators. This is due to a bug/behaviour of ENOVIA.
For example the expression shown below:
<Expression>attribute[Attribute 1] == Value1 || attribute[Attribute 2] == Value2</Expression>
Might need to be rewritten as shown below:
<Expression>attribute[Attribute 1] == Value1 *OR* attribute[Attribute 2] == Value2</Expression>
E.g. the operators || and && could be changed to OR and AND.
To verify your expressions, you can from MQL do:
<MQL> pri bus T N R select evaluate[attribute[Attribute 1] == Value1];
NOTE 3: If your expression should be evaluated against the connections instead of over the business objects, which is the default, then you can say so as shown below:
<Filter usesBusinessObject="false" ...>
To use a custom loader within a data-set that is implemented in Java, this can be done through the example below:
<Java className="com.acme.MyDataLoader"/>
The class specified must implement one of the interfaces below:
com.technia.tvc.core.db.dataset.loader.DataLoader
com.technia.tvc.core.db.dataset.loader.DataLoaderWithInput
If your custom Java class supports load by a child loader, you need to implement the DataLoaderWithInput interface.
The source objects as provided by the client through for example request parameters will be used by the data-loaders that require input, but doesn’t have any input configured in the data-set XML file through any child loaders, implicitly.
To explicitly define that you will use the source objects, then you can define this in the Data set XML file like shown below:
<Filter>
<Expression>...</Expression>
<Source/>
</Filter>
The id of the person object associated with the current user can in some cases be useful to start from when for example expanding a structure. Below is an example how to use it:
<EndItems>
<Expand>
...
<PersonObject/>
</Expand>
</EndItems>
This example will expand the person object and finally filter out all rows in the structure except for the "end items".
The id of the company object associated with the current user can in some cases be useful to start from when for example expanding a structure. Below is an example how to use it:
<EndItems>
<Expand>
...
<CompanyObject/>
</Expand>
</EndItems>
This example will expand the company object and finally filter out all rows in the structure except for the "end items".
In some cases when you have expanded a structure, you only want to remove the root nodes. This can be accomplished as shown below:
<RemoveRoots>
<Expand>
...
</Expand>
</RemoveRoots>
The "RemoveRoots" element doesn’t have any configuration options.
A dataset might use the outcome from another dataset. This can be accomplished as shown below:
<DataSetRef name="tvc:dataset/MyDataSet.xml">
In conjunction with the Flatten loader, which converts a structure into a flat list, you can use the Structure loader to convert a flat list into a structure.
Each row in the flat list used as input to this loader will be set as root node in the returned structure.
Note that if the input to this loader is a structure, no change is made.
You can configure this loader with some additional attributes:
| Attribute | Description |
|---|---|
ignoreRelIds |
A Boolean specifying if to exclude any relationship information as provided by the child loader. Default is false. |
Example:
<Structure ignoreRelIds="false">
<Query>
...
</Query>
</Structure>
To combine the result from several loaders, you can use the "Union" loader. This can be accomplished as shown below:
<DataSet>
<Union>
<DataSetRef name="tvc:dataset/Example.xml"/>
<Query>
<TypePattern>
<Type>type_SomeType</Type>
</TypePattern>
<FindLimit>10</FindLimit>
<Where>current == Obsolete</Where>
</Query>
<Query>
<TypePattern>
<Type>type_AnotherType</Type>
</TypePattern>
<FindLimit>10</FindLimit>
<Where>current == Create</Where>
</Query>
<Query>
<TypePattern>
<Type>type_ThirdType</Type>
</TypePattern>
<Where>current == Release</Where>
<FindLimit>10</FindLimit>
</Query>
</Union>
</DataSet>
In this example, we combine the result from three queries and the result from a referenced data-set.
If any of the loaders contains structural data, the outcome of this loader becomes a structure.
To force flat list, you can use the attribute "forceFlat" on the <Union>
element and set the value to true. E.g.
<DataSet>
<Union forceFlat="true">
This loader will return the ID’s that are part of all child loaders. Example:
<DataSet>
<Intersection>
<DataSetRef name="tvc:dataset/First.xml"/>
<DataSetRef name="tvc:dataset/Second.xml"/>
</Intersection>
</DataSet>
The result from the example below will contain the objects that are in both the results from the specified data-sets.
By default, this loader uses the object-id’s. However, you can configure it to use the relationship id’s instead. This is accomplished as shown below:
<DataSet>
<Intersection useRelationship="true">
To exclude data from a loader, you can use the Complement-loader. It allows you to define nested loaders, which defines the maximum objects/connections to be included. From this maximum set, you can exclude objects/connections.
See the example below which queries the system for all Person objects, but excludes the one representing the current user.
<Complement>
<Include>
<Query>
<TypePattern>
<Type>type_Person</Type>
</TypePattern>
</Query>
</Include>
<Exclude>
<PersonObject/>
</Exclude>
</Complement>
Both the <Include> and <Exclude> elements accepts multiple loaders.
By default, any data loader within a data set is run with the same context (credentials) as the user who is logged in. In some cases, you might want to run a query as a super user in order to by-pass any access checks that are expensive to evaluate. To do so, you can accomplish this as shown below:
<DataSet>
<DoPrivileged>
<Query>
...
</Query>
</DoPrivileged>
</DataSet>
This loader is used to get only the latest revision of the object which is in the specific state. For example this can be used to only get the latest "Released" revision of a part. Example of this scenario:
<DataSet>
<LatestInState>
<State>Released</State> (1)
<Query>
<TypePattern>
<Type>Part</Type>
</TypePattern>
...
</Query>
</LatestInState>
</DataSet>
| 1 | State definition |
As of TVC 2015.3.0, support for parameterize values in a data set has been added. This feature can be used to let end users affect the result of a dataset, for example specify different type pattern in a query or change something in a where expression. Depending on how the data-set is being used, these parameters are resolved differently but typically in the web-environment these parameters originates from a request parameter.
By default, all data-sets are allowed to be parameterized. This behavior can be changed via a so called TVC init parameter. The name of this parameter is shown below and its default value is "TRUE".
tvc.core.dataSet.defaultParameterizable
The support for parametrization can be defined on a per-dataset basis also. See example below how to configure it.
<DataSet parameterizable="true | false">
The default value is controlled via the global parameter.
The syntax of a parameter is:
$(paramName,options)
Options is a comma separated list of options. An option consists of a key and value separated with the equals character. The available options are listed below:
| Option | Description | Example |
|---|---|---|
type |
Specifies the datatype of the value. Supported types are:
Note 1: date is used to convert a ISO8601 date to a ENOVIA date Node 2: The type value accepts symbolic names |
type=integer |
default |
Specifies the default value to be used if omitted or value is empty and empty is "false" |
default=type_Part |
derivedFrom |
If type is either type or relationship, this option may be used to specify that the value must represent a type that is derived from this type. |
type=type,derivedFrom=type_ECO |
empty |
Defines if the empty string is allowed or not. Default is FALSE. |
empty=true |
multiple |
Defines if multiple values are allowed. Default is FALSE |
multiple=true |
separator |
If multiple values are allowed and there are multiple values present, these values are concatenated with a separator string. Default value is the comma character. |
multiple=true,separator= |
escape |
If set to true, the resolved value will be searched for MQL sensitive chars to be escaped. The chars that are escaped are quote, double-quote and back-slash characters. Default is false. |
|
escape=true |
min |
For integers or numbers: provided value must not be lower than min value For strings: Length of string must be longer or equal to min. |
min=1 |
max |
For integers or numbers: provided value must not be greater than the max value. For strings: Length of string must be shorter or equal as the max value. |
max=5 |
allowWildcard |
If set to true and type is string, the input string is considered invalid if it contains either a ? or * character. |
Below are some examples of how the parameterized values can be used.
Example where the expand properties are parameterized.
<DataSet parameterizable="true">
<Expand>
<From>$(param.expandFrom,type=boolean,default=false)</From>
<To>$(param.expandTo,type=boolean,default=false)</To>
<Depth>$(param.depth,type=int,default=3)</Depth>
<TypePattern>
<Type>$(param.type,multiple=true,default=type_Part,type=type,derivedFrom=type_Part)</Type>
</TypePattern>
<RelationshipPattern>
<Relationship>$(param.rel,multiple=true,default=relationship_EBOM)</Relationship>
</RelationshipPattern>
</Expand>
</DataSet>
Another example using an inquiry.
<DataSet parameterizable="true">
<Inquiry>
<Code>temp query bus "$(typePattern,default=*,multiple=true)" * * limit 100 select id dump |</Code>
<Pattern>*|*|*|${OID}</Pattern>
<Format>${OID}</Format>
</Inquiry>
</DataSet>
Most but not all configuration parameters within the DataSet XML definition allows specifying parametrization macros. The table below shows the supported places.
| Element | Property |
|---|---|
<DataSetRef> |
Referenced data-set |
<Expand> |
|
<Filter> |
Filter expression |
<Inquiry> |
|
<JPO> |
|
<LatestInState> |
State value |
<MQL> |
Code |
<Query> |
|
Since the DataSet’s now may contain special macro references using $()
keywords, you may in rare situations need to escape such keywords if you
don’t intend to resolve it as a macro.
Fortunately you can either disable parametrization completely on that particular DataSet or escape these sensitive characters using the backslash key.
For example:
<DataSet>
<MQL>
<Code>\$(something)</Code>
Note that if you today are using backslashes, these are now treated as escape chars and hence you would need to escape the backslash also. So be aware of the following
Presence of $(
Use of backslash
TVC will as of the 2011.2.0 version adopt the UI to be closer to the UI as of V6R2012 if TVC is used together with this ENOVIA version. If TVC is used with an older version of ENOVIA, the standard look and feel of TVC is used.
E.g. TVC will adjust look and feel depending on ENOVIA version used.
To support this, we have added support for so called themes within TVC. Currently, we support the following themes within TVC:
classic
v6r2012
v6r2013x
v6r2014x
v6r2015x
In future releases of TVC, we plan to develop other themes as well.
Unless a specific theme has been configured to be used, the theme-manager within TVC will decide what theme it will use by default by checking the ENOVIA version.
To explicitly specify what theme to be used, one can apply the following init-parameter to the TVC servlet in WEB.XML:
<init-param>
<param-name>tvc.core.theme.current</param-name>
<param-value>classic</param-value>
</init-param>
NOTE: You can configure TVC to use the V6R2012 theme even if you aren’t using this ENOVIA version. However, this should not be done, since the CSS files within the V6R2012 theme is referring to images that is provided by ENOVIA V6R2012.
It is also possibly to switch theme at runtime. A person with administration privileges can execute the following URL to do so:
${ROOT_DIR}/tvc-action/changeTheme
Calling this URL will give a screen allowing the administrator to change the theme among the available themes.
| The support for different themes has resulted in that all style sheets (CSS files) used across all TVC components has been renamed, moved and divided into several files. If you for some reason have used our CSS files, the HREF’s to those CSS files will as of this release be broken. |
If you want to use a stylesheet in TVC, you should never do that by the path to the file. Instead, one should use the "id" of the stylesheet as defined in the theme configuration files within TVC.
To reference a stylesheet from a JSP page, one will do as shown below:
<%@ taglib uri="/WEB-INF/tvc-core.tld" prefix="core" %>
...
<core:themeArtifact id="id-of-artifact"/>
<core:themeArtifact id="id-of-another-artifact"/>
To reference a stylesheet from a renderer (java class), one typically do:
import com.technia.tvc.core.gui.resource.Resource;
import com.technia.tvc.core.gui.resource.ThemeArtifact;
...
Resource resource = new ThemeArtifact("id-of-artifact");
Note that a theme artifact associated with an ID, might refer to one or several different files at the end. This might also vary depending on the current theme. E.g. the same artifact ID might result in three CSS files for theme A, while for theme B, it might result in two CSS files.
Below is a compressed list of common CSS files with their path used from the previous release of TVC and their new "artifact id" reference to be used as of 2011.2.0.
| Old Path (Before 2011.2.0) | Reference ID (as of 2011.2.0) |
|---|---|
/tvc/core/styles/tvcUIDefault.css |
tvc-ui-default |
/tvc/core/styles/tvcForm.css |
tvc-form |
/tvc/structurebrowser/styles/tvcTablePreferences.css |
table-preferences |
| If you have referenced another CSS file not in the list, please consult Technia for information how to reference it correctly as of 2011.2.0. |
The autocomplete makes it easier to enter values in fields. It can be used for example when specifying what kind of Part the user wants to create, enter the Responsible Design Organization (related object) for a part or select units of measure for a part (ranges of attribute).
On server side the AutoCompleteHandler (handler) is responsible for providing available values for a field. The value consist of the actual value that is stored in the database, ex. object id, and a display value which the user is presented with. TVC comes with a number of built-in handlers.
Selectize is used on client side to render the field where user can enter values along with the dropdown containing available options. The plugin has a high level of configurability making it possible to set for instance how many options that should be presented, how to render them, ordering of options and much more.
This autocomplete documentation applies to Top Panel, Structure Browser tables and Create/Edit Forms.
There are two categories of settings:
Selectize. These controls the behaiour of the Selectize plugin. See the Selectize usage page for a full reference.
AutoCompleteHandler. Defines settings for the handler. Handler settings are wrapped in a handler object to don’t collide with Selectize settings. These settings are described in detail in the following chapters.
Use lowercase name of handler when specifying handler to use.
Common settings for all handlers:
| Name | Description | Default |
|---|---|---|
name |
Defines the AutoCompleteHandler to use. Enter the name of a built-in handler or specify the qualified name of your java class. |
user |
caseSensitive |
Defines if searches are case sensitive. |
false |
contains |
Must the value start with the search criteria. |
true |
limit |
Maximum amount of results that is returned from server. |
50 |
localize |
| Name | Description | Default |
|---|---|---|
assignments |
Users must be assigned the role/group to be displayed. |
|
returnOid |
Returns the object id instead user name as value. |
false |
| Name | Description | Default |
|---|---|---|
rootTypes |
Defines types to be searched. All sub types are also searched |
All types |
returnAbstractTypes |
Defines if abstract types should be searched. |
false |
Uses a dataset to define available search options. If the field is in context of an object, e.g. in a top panel, the object id will be available in the dataset. This makes it possible to do operations which requires input, e.g. expansions.
| Name | Description | Default |
|---|---|---|
dataset |
Name of the dataset to use. The settings is mandatory. Example:
|
|
value |
Select expression selecting the value |
id |
label |
Defines what data to use as label. Supports macros. Examples:
|
|
select |
Defines additional data to fetch and return to the UI. Add one or more select expressions. Supports macros. The selected data can be used to make more advanced option rendering at the client using the Selectize settings rendering. Examples:
|
Example using dataset handler in Forms:
<ConnectField>
<Label>Part Family</Label>
<Relationship>
<Name>relationship_ClassifiedItem</Name>
<Direction>to</Direction>
</Relationship>
<AutoCompleteHandler>dataset</AutoCompleteHandler>
<AutoCompleteSettings><![CDATA[{
handler : {
dataset : 'tvc:dataset:tvx:enc/PartFamilies.xml',
value : 'id',
label : '$<name>'
}
}]]></AutoCompleteSettings>
</ConnectField>
Searches for business objects using a query. Most often you enter some criteria to limit the search result, for example you will add a typePattern and whereClause to only get the first revision of parts.
| Name | Description | Default |
|---|---|---|
typePattern |
Type pattern to search for. |
|
namePattern |
Name pattern to search for. |
|
revisionPattern |
Revision pattern to search for. |
|
vaultPattern |
Vault pattern to search for. |
|
whereClause |
Where clause to use. |
|
matchOn |
||
expandType |
True |
|
displayMacro |
||
searchType |
How the search criteria will operate. Available values: * contains * startsWith * endsWith |
Custom rendering of options using dataset handler in Forms:
<ConnectField>
<Label>ECO to release</Label>
<Relationship>
<Name>relationship_AffectedItem</Name>
<Direction>to</Direction>
</Relationship>
<AutoCompleteHandler>dataset</AutoCompleteHandler>
<AutoCompleteSettings><![CDATA[{
'handler' : {
'dataset' : 'tvc:dataset:tvx:enc/ECOs.xml',
'value' : 'id',
'select' : ['$<name>', '$<attribute[attribute_Severity]>', '$<attribute[attribute_Priority]>']
},
'labelField' : 'name',
'searchField' : ['name', 'select_2', 'select_3'],
'render' : {
'option' : function(item, escape) {
var option = [];
option.push('<div style="border-bottom: 1px solid #ccc;">');
option.push(escape(item.name)
+ "<br/><b>Severity:</b> "
+ escape(item.select_2)
+ "<br/><b>Priority:</b> "
+ escape(item.select_3));
option.push('</div>');
return option.join('');
}
}
}]]></AutoCompleteSettings>
</ConnectField>
| Select statements are replaced with select_1, select_2 and so on. This is done because complex select statements doesn’t comply with JSON naming standards. |
The TVC components can produce log output that can be useful for debugging purposes.
TVC uses Log4J internally to handle the logging. It is possible to define how much logging you want, by defining a so called log-level, this can be set for either all TVC Components or just for a particular component (this can be done on class-level as well).
TVC will configure Log4j to write all logs into a log file called "tvc.log" and in addition also write the logs to the console. Note that depending on your application server setup, either standard out/err are redirected to separate log files or directly to the console.
The logging output from TVC could be configured. Default, only problems that are fatal are displayed within the log files.
The init-parameter that controls the log output for all TVC Components is defined as below:
<init-param>
<param-name>tvc.core.logLevel</param-name>
<param-value>DEBUG</param-value>
</init-param>
This will enable DEBUG output from all components (and generate a lot of output).
Following examples illustrates how to define different log levels for different components:
Enable debug output for TVC Core:
<init-param>
<param-name>tvc.core.logLevel.com.technia.tvc.core</param-name>
<param-value>DEBUG</param-value>
</init-param>
Enable debug output for the Structure Browser:
<init-param>
<param-name>tvc.core.logLevel.com.technia.tvc.structurebrowser</param-name>
<param-value>DEBUG</param-value>
</init-param>
Enable debug output for the Report Generator:
<init-param>
<param-name>tvc.core.logLevel.com.technia.tvc.reportgenerator</param-name>
<param-value>DEBUG</param-value>
</init-param>
The log-level can be changed meanwhile the application server is running. This is done by entering an URL in the browser (note that you must be logged on as a user with administration possibilities).
http(s)://server:port/ematrix/tvc-action/setLogLevel?logLevel=DEBUG
Optionally, the parameter logDomain could be added to explicitly define a specific component (same as for the web.xml configuration).
The possible values for the log levels are:
ALL
DEBUG,
INFO
ERROR (default)
FATAL
WARN
OFF
| Remember that extensive logging will slow down the TVC functionality dramatically; verbose logging should only be used for problem solving. |
Example:
/tvc-action/setLogLevel?logLevel=DEBUG&logDomain=com.technia.tvc.core
The logging output can be extended to contain user name (the Matrix user name) and the IP address of the user. This feature is by default disabled, and can be enabled by:
Adding an init parameter to the servlet like below:
<init-param>
<param-name>tvc.core.logUser</param-name>
<param-value>TRUE</param-value>
</init-param>
TVC has a built in status monitor, which could be used to show information about the system you are running, and information about all the components that have been installed.
The status monitor is reached by requesting the following URL from your browser:
http(s)://server:port/ematrix/tvc-action/monitorStatus
The URL is only available for a person logged in having either system- or business- privileges, or is a member of the AEF role "Administration Manager".
A convenient command exists in the UI (found under the Admin Tools menu), which can be used to collect the server log files within a ZIP file (including system settings and TVC settings).
This feature will collect as many log files as possible; e.g. if running in RIP mode, also the Matrix log files are included.
To include a custom directory (or custom directories), add the following init-parameter (value is a pipe separated list of directory names):
<init-param>
<param-name>tvc.core.collectLogFiles.customDirectories</param-name>
<param-value>c:/logs|d:/logs</param-value>
</init-param>
TVC Ajax framework uses XML also as data transport format. Sometime if the text is copied from source like PowerPoint might contains chars which are invalid according to XML specification might break the TVC Ajax operation.
TVC supports filtering such invalid XML chars. This feature is by default disabled, and can be enabled by adding an init parameter to the servlet like below:
<init-param>
<param-name>tvc.core.xml.ajax.filterInvalidXMLChars</param-name>
<param-value>TRUE</param-value>
</init-param>
As of the 2011.2.0 release, TVC has been qualified for ENOVIA V6R2012. The look and feel of TVC has also been adapted to the new standards as of V6R2012.
If you are using or planning to upgrade to V6R2012, you should pay attention to some flaws with this release of ENOVIA discussed in the sub-chapters below.
The category tree has been replaced with a toolbar menu. Commands that previously were shown in the left-hand category tree now appear in a toolbar menu.
There is a bug with the ENVOIA toolbar implementation that results in that the ID of the object is not passed correctly to all toolbar-commands. When you have commands in this menu whose HREF doesn’t contain a reference to a JSP page (like the example below), then the parameters are not added to the HREF as it should.
${ROOT_DIR}/tvc-action/someAction?param=value&anotherParam=value
The work around for this bug is to add a bogus page reference to the HREF as shown below:
${ROOT_DIR}/tvc-action/someAction/abc.jsp?param=value&anotherParam=value
^^^^^^^^
E.g. adding something ending with .jsp will cause the ENOVIA toolbar to add the required parameters. Note that you need an additional slash character before the actual "jsp page" name.
This doesn’t have any impact on TVC itself, since the only important token is what appears after the "tvc-action/" string up to the next slash. The added JSP page is ignored.
NOTE: Commands in the category menu calling TVC should not have the setting "Submit" set to TRUE. This will cause other irrelevant parameters to be passed into TVC possibly overloading parameters typically defined in configuration objects used by the different TVC components (for example page-configurations, grid browser configurations etc.). This setting were not used previously when the left-hand category tree were used, so all commands needs to be reviewed to ensure that they don’t have this setting applied.
As of ENOVIA 2012 and later, the user interface does not have the left hand tree containing the functions available for a particular object. Instead, these functions have been moved into a category menu.
TVC has now support for the category menu in the following places.
Core
Top Panel
Tabbed Pages
Wiki
Grid Browser
Structure Browser
Structure pages
Flat table pages
Forms in Content Mode
Report Generator
Graphic Reporting
Dashboard
Gantt Chart
Below are some example screenshots showing how the category menu appears in different pages.
Top panel with category menu
Report Generator List Page with Category Menu
Structure Browser with Category Menu
The category menu will appear if the request parameter called "categoryTreeName" is available in the request (passed by default by ENOVIA). There are two options available for disabling the category menu even though it is being passed.
Per request: Add another request parameter called "disableCategoryMenu" and set this to true.
Globally: Add an init-parameter in TVC called
tvc.core.db.aef.useCategoryMenu and set this to either true or false.
Default is "auto-detect", meaning that TVC will query the
emxSystem.properties file for the property emxFramework.LegacyUI.
When a Non-Modal page is opened from a page (parent) (Ex: add existing), the page is registered to the parent page to get closed when the parent is closed or reloaded. This is done to avoid hanging dependent pages whose source page is not available. Ex. Add existing cannot be completed if the opener page is no more.
But not all the pages opened from a page is dependent pages. There are many independent pages whose behaviour does not depend on the parent page. Ex: emxTree.jsp or emxNavigator.jsp or /loadTopPanel etc.
So If a page is identified as generic or independent page it is registered to the top most page (Ex: emxNavigator.jsp) to get closed upon log off or browser close.
Currently all pages starting with "/emx" are considered independent pages. This behavior can be controlled via a URL parameter named "independent=false" or "independent=true". With "independent" URL parameter any custom or existing page close behavior can be controlled.
In ENOVIA 2015x and above, it can be problematic to load a page into the "content" frame and at the same time hide some of the user interface related to page headers etc.
Example shown in screenshot below.
For example if you have loaded an object specific page, you might have the categories to the left and some extended page header area above. This is examplified in the screenshot below.
Simply having the Target Location setting on the command set to content will not result in that the extra area highlighted above is made hidden.
TVC contains a JSP page that will help to work around this problem. Instead of calling your page directly, you can do as shown in the example below:
MQL<1>pri command TVXHomePage;
command TVXHomePage
description
label 'TVX Home Page'
href '${ROOT_DIR}/tvc/core/enovia/LoadContentPage.jsp?page=tvc-action/tvxPersonalTopPanel/foo.jsp?panel=tvc:toppanel:tvx:common:toppanel:personal/PersonalHomePage.xml'
setting Target Location value content
user all
nothidden
created 4/26/2016 3:18:57 PM
modified 4/27/2016 10:02:42 AM
E.g. you can load the page ${ROOT_DIR}/tvc/core/enovia/LoadContentPage.jsp
that first will reset the view before loading the page as provided via the page parameter.