21 March 2016

This page contains answers to common questions related to the TVC components.

Table of Contents

1. TVC General

1.1. Can TVC be used in an environment the doesn’t have AEF/BPS installed?

Yes. With the exception of some components like:

  • XBOM Manager

    The XBL feature in XBOM Manager could be used but the installation of XBOM will fail due to missing datamodel entities such as type-Part and relationship-EBOM. This issue will be fixed in the future.

  • ECO/ECR Manager

  • MCAD Optimizer

Office Integration works, but will require some additional configuration as the CDM (Common Document Model) is not in place.

Some additional configuration is required though.

You need to add some init-parameters to WEB.XML within the TVC Servlet definition. The init parameters are defined as below:

<init-param>
    <param-name>name-of-parameter</param-name>
    <param-value>value-of-parameter</param-value>
</init-param>

Following table shows the parameters you need, and some description:

Parameter Name Description Example

tvc.core.host

The connection to Matrix (leave empty for RIP mode)

rmi://hostname:1099

tvc.core.dateTimeFormat

The date format used in Matrix (used when parsing date values from/to Matrix into Java date objects)

yyyy-MM-dd HH:mm:ss

tvc.core.inputDateTimeFormat

The input date format

yyyy-MM-dd HH:mm:ss

ematrix.web.app

Just set this value to TRUE as this is related to how TVC generates links

TRUE

ematrix.page.path

Specify the "context" path to the application. Normally, this should be the value as obtained from "request.getContextPath()" but due to the way AEF/BPS is configured this parameter must be set here too.

/application

ematrix.login.page

The login page that is used in the application.

/login.jsp

tvc.core.setRequestCharacterEncoding

This setting will (if you use Tomcat) set the character encoding to the request object. + This is handy, as you otherwise would need either a filter (as used in ENVOIA), or modify the server.xml (Tomcat config file) to specify the requestURI encoding.

true

1.2. How can TVC be uninstalled?

There is no automated process for this, it has to be done manually.

  1. From the web-application, remove these files (or folders)

    • /tvc

    • /WEB-INF/tvc-*.tld

    • /WEB-INF/tvc

    • /WEB-INF/lib/tvc-*.jar

    • /WEB-INF/classes/tvc.license

  2. Remove the schema entities

    This is a bit trickier, but not impossible.

    There is a program in the database that might help you. It’s not 100% reliable (and it is not supported really). The program is called TVCSchemaUninstaller

    Basically, what it does is:

    • Export the TVC Admin vault

    • Clear and Tidy this vault

    • Delete the vault

    • Delete roles

    • Delete TVC Shadow Agent User

    • Delete attributes

    • Delete policies

    • Delete types (start from the lowest type in the tree hierarchy)

2. Core

2.1. Can the "TVC Shadow Agent" be replaced with "User Agent" as this user will not consume a CPF license?

Yes.

This can be done in a couple of different ways, see explanation below:

Add init parameters to the tvc-servlet within "web.xml" like the example below:

<init-param>
    <param-name>tvc.core.user</param-name>
    <param-value>User Agent</param-value>
</init-param>
<init-param>
    <param-name>tvc.core.password</param-name>
    <param-value>the-password</param-value>
</init-param>

This alternative is sometimes not OK as you store the password within the web.xml file in clear text.

Instead you can do:

  1. Modify a program called "TVCInitSystemUser".

    This program holds the user-name and password (in encrypted format) as properties, and is read when TVC is started (unless you have configured a user/password as described above).

    From MQL; you can do:

    pri program TVCInitSystemUser;

    This gives something like:

    program TVCInitSystemUser
    mql
    execute immediate
    execute user
    description
    code '#@ version 1.0 name TVCInitSystemUser symname program_TVCInitSystemUser
    tcl;
    eval {
        set sProgName [DEV:mql get env 0]
        set sUserName [mql pri program $sProgName select property[DEV:USER_NAME].value dump |mql pri program _sProgName select property-(USER_NAME-).value dump -]
        set sUserPass [mql pri program $sProgName select property[DEV:USER_PASS].value dump |mql pri program _sProgName select property-(USER_PASS-).value dump -]
        return "$sUserName|$sUserPass"
    }'
    nothidden
    property USER_NAME value TVC Shadow Agent
    property USER_PASS value =uvZVYq2ODJU=
    property application value TVC core
    property installed date value 11-19-09
    property installer value Technia AB
    property original name value TVCInitSystemUser
    property version value 1.0
    created 11/19/2009 10:49:18 PM
    modified 1/20/2010 2:03:23 PM

    You could change the USER_NAME property and USER_PASS property. The value for the latter is the encrypt password value.

    tcl;
    mql mod program TVCInitSystemUser property "USER_NAME" value "User Agent";
    mql mod program TVCInitSystemUser property "USER_PASS" value [mql encrypt password "the-password"];

2.2. If you modify the roles of person, it seems that we must clear the TVC cache before the change is fully noticed by TVC, why?

The role/group assignment to a person is cached in TVC in order to reduce the need for accessing the DB to get this information. Clearing the TVC Cache will of course clear this info, however, it will also clear everything that doesn’t need to be cleared.

A better alternative is to use the below methods:

com.technia.tvc.core.db.model.PersonInfo.clearCacheForPerson(String userName)

Or, use this method:

com.technia.tvc.core.db.model.PersonInfo.reloadCacheForPerson(String userName)

Alternatively, you can also do this for all persons by using one of the two alternatives below:

com.technia.tvc.core.db.model.PersonInfo.clearCache()

Or,

com.technia.tvc.core.db.model.PersonInfo.reloadCache()

The first call is fast, while the latter will take some time as it needs to reload the cache for all persons.

2.3. What are your findings/recommendations in handing symbolic names?

The "core" class in TVC that does the name lookup is called com.technia.tvc.core.db.aef.naming.Naming

This method has a couple of methods for resolving symbolic names. All these are cached after first retrieval (until the TVC cache is cleared). The drawback with these methods (on the Naming class) is that those requires a "Transactional Context" to be allocated.

2.4. I’ve noticed that you are using SymbolicName as well as ParsedStatement. Is that your recommendation in general?

These classes serves different purposes.

SymbolicName is a wrapper class around the "Naming" and it represents a single symbolic-name / resolved-name value.

The SymbolicName caches the resolved value and sub-sequent retrieval of the value does not require transactional context to be available. Normally, the SymbolicName is used as "static final" fields in a class/interface:

public static final SymbolicName type_Part == new SymbolicName("type_Part");

One can provide a default value as the second argument, in order to use this value if the name-lookup fails for some reason.

To get the real name, simply do:

type_Part.get()

The ParsedStatement is typically used to define select statements containing symbolic names. For example:

private static final ParsedStatement documentClassification =
    new ParsedStatement("$<from[relationship_DocumentRel].to.attribute[attribute_Classification]>");

To get the real select statement, one simply do:

documentClassification.get();

It works in a similar way as SymbolicName; e.g. the parsing is done once only.

The rule for both SymbolicName and ParsedStatement is that these should be used as static-final fields. If used as field in a method, it’s advantage is less as the parsing will be done more than one time for the same expression.

2.5. Are the caches in behind utilizing the ENOVIA cache?

No. TVC is not dependent on any class within the AEF/BPS nor any central (except for some data model specific code, which exists in our XBOM Manager and ECO/ECR Manager components).

The only dependency TVC has, is against the ENOVIA-ADK classes.

Also, the TVC caches are better and more intelligent. The ENOVIA caches are loaded on server startup, which is the reason why the first login takes huge amount of time.

TVC caches are loaded on demand.

2.6. How do I clear the TVC cache?

The TVC installation adds commands to a menu called “Admin Tools”, including the “Clear TVC Cache” command. But this depends on that menu (menu_AEFAdminToolsMenu) existing.

If, for some reason, that’s not there (due to access, or other reasons), it can be done manually by using this URL:

/tvc-action/clearCache

2.7. Could i configure Top Panel with submit and cancel buttons?

No, Top Panel is inplemented to update directly (same as the Structure Browser)

3. Structure Browser

3.1. How do I set up Dynamic Columns?

Basically, the columns are created by the so called TableFactory. You can specify your own factory via parameter:

tableFactory=com.acme.foo.MyTableFactory

Implement the table factory:

Extend TableFactory to implement loadTable. You can create a configurable table using a normal table definition as template and dynamically add columns to that definition.

private static class MyTableFactory extends TableFactory {
    public Table loadTable(Object resource, Environment env) throws TVCException {
        TableFactory baseFactory = TableFactory.getInstance();
        Table base = baseFactory.loadTable(tableBase, env);
        ConfigurableTable table = ConfigurableTable.createFromTemplate(base, env);

        ColumnSettingsImpl cs == new ColumnSettingsImpl();
        s.setNoWrap(false);
        ConfigurableColumn col == table.addColumn(cs,env);
        col.setExpression(…);
        col.init();
        return table;
    }
}

3.2. What does the settings Submit and SubmitOID really mean?

In short:

Submit

Includes info about the selected rows from the structure browser in the URL specified in the command (request parameter: emxTableRowId)

Submit OID

Includes the object-id of the object used to launch the structure browser for. (request parameter: objectId)

Detailed:

When the user wants to perform an action (such as invoking a command from the context-menu or the tool-bar), the action typically applies to the selectedrows in the structure browser.

In order to instruct the Structure Browser to include these selected rows in the request when calling the action, one need to set the "Submit" setting on the command to TRUE. Note: In case you use XML commands/menus, the tag is called <SubmitForm>.

This implies that all the selected rows are submitted under the request parameter "emxTableRowId" (same as used in the centrals). The format of this parameter is:

emxTableRowId=<object-id>

In case when the row(s) only has information about the object

emxTableRowId=<relationship-id>|<object-id>

In case when the row(s) has information about both a connection and object

emxTableRowId=<relationship-id>|<object-id>|<parent-object-id>

This format was introduced in TVC 2009.1.0 in order to improve compatibility with AEF (or BPS) as they include the parent object-id also.

This format will be used in case when you submit from a strucuture page

in the ENOVIA structure browser, there is a fourth parameter that looks like |1,0. Currently, we don’t support this as the meaning of this parameter is not well defined. This however might lead to problems invoking an action that is used in the OOTB ENOVIA Structure Browser.

If you set the "Submit OID" setting to true, the id of the object used to launch the structure browser with, will be included in the request. That id will be passed using the "objectId" request parameter.

The reason why we don’t submit this always, is that some commands work in the way to first check the "objectId" parameter and if not found check the "emxTableRowId" parameter. If we always would pass "objectId", those commands would start to behave wrongly.

3.3. Can I display data in a Structure Browser table, which does not relate to a business object nor a connection?

Yes. This is achieved by implementing a so called "TableModel" or "TreeTableModel" (similar to what’s in the javax.swing world).

Flat List View = table-model
Structure View = tree-table-model

Depending on the model used; one will need to use different actions (URLs):

/tvc-action/tableWithModel
producer=com.acme.producer.MyTableModelProducer

And

/tvc-action/structureWithModel
producer=com.acme.producer.MyTreeModelProducer

Where "producer" is a request parameter holding a class name.

The table-model producer interface is defined like:

package com.technia.tvc.structurebrowser.model;

public interface TableModelProducer {

    TableModel produce(HttpServletRequest req) throws TVCException;
}

The tree-table-model producer interface is defined like:

package com.technia.tvc.structurebrowser.model;

public interface TreeTableModelProducer {
    TreeTableModel produce(HttpServletRequest req) throws TVCException;
}

The TableModel and TreeTableModel interfaces are defined in the following packages:

  • com.technia.tvc.core.table.model

  • com.technia.tvc.core.structure.model

There are some abstract implementations of these interfaces, which makes it easier for you to implement your own code.

Look for AbstractTableModel, SimpleTableModel, AbstractTreeTableModel and SimpleTreeTableModel in the Java Docs available in TVC Developer docs.

3.4. Can I configure the behaviour of the 'target' table in Build Structure, such as changing view/toolbar etc?

No, this is not configurable today. The target table-bean is a "clone" of the table-bean that you start the build-structure from.

We however do some changes to the cloned copy, such as changing the header/sub-header and modifying some properties on the "Page Config" instance.

If you want to customize this; then you have to do some (minor) coding:

Create an action class that is derived from the base class

com.technia.tvc.structurebrowser.buildstructure.actions.StartBuildStructureAction

Maybe call this com.acme.actions.CustomBuildStructureAction

Add a mapping to this action class within your own "Action mapping" file (never change the one in the component) Define this like the example below:

<action path="/customBuildStructure" type="com.acme.actions.CustomBuildStructureAction">
    <forward name="frameset" path="/tvc/structurebrowser/buildstructure/tvcSearchFS.jsp" />
    <forward name="autoLoad" path="/tvc/structurebrowser/buildstructure/tvcSearchFS.jsp?autoLoad=true"/>
</action>

Finally, overload the method getTargetTable(HttpServletRequest) like below:

protected TableBean<?> getTargetTable(HttpServletRequest request) throws TVCException {
    TableBean<?> t == super.getTargetTable(request);
    /*
     * Do whatever you need here...
     */
     return t;
}

3.5. My table does not have a default sort column even though I tried using the sortColumnName parameter?

Since a pageconfig can have multiple views with multiple tables, it rely upon column settings instead of using an href parameter (as used by the ENOVIA tables); it would be difficult to define default sort column for all tables in all views using just request parameters. To use, add the Sort Direction setting to the column that you would like to sort on by default; if you have multiple columns that should be sorted on, also use the Sort Order setting to define the order of the sort.

Note that SB will remember which columns a user sorted on and auto apply these on the next visit, so the default sort settings will typically only apply for your first visit to a page, after that it will use the sort order from the personalization data.

3.6. So how do I make it so my table does NOT remember my personal sort order for columns?

Remembering column sorting and column visibility on user level can be globally switched on/off using the following init parameter to the tvc-servlet in the "web.xml":

<init-param>
    <param-name>tvc.structurebrowser.rememberSelections</param-name>
    <param-value>true</param-value>
</init-param>

The default value is true.

It’s also possible to control this on a pageconfig level by adding the "selectionTracking" parameter:

<PageConfiguration>
    <Parameters>
        <Parameter name="selectionTracking" value="false" />
    </Parameters>
</PageConfiguration>

The global setting in combination with the setting per pageconfig decide whether user selections should be remembered or not.

3.7. How do I make structure browser initially expand all?

Add the postprocess expandAll parameter to your pageconfig parameters or command URL

3.8. I’m using a column editable program but it is never called, why?

The reason below is that you are using a custom datahandler. The default datahandler usually takes care of the editable program invocation. My suggestion is that you add the editable logic directly to the custom datahandler or invoke the JPO from there.

<Column usesBusinessObject="false">
    <DataHandlerClass>com.MyHandler</DataHandlerClass>
    <EditableProgram>MyJPO</EditableProgram>
    <EditableFunction>myMethod</EditableFunction>
</Column>

3.9. I want to control the available toolbar commands by selected row type, how?

This feature is only available for right click context menus. For toolbar actions you need to handle this in the action (and notify user?).

3.10. Is it possible to retain row selectoins over paginated pages?

Try using a selection behaviour to update values in bean. Then use bean values rather than request parameters in your actions.

3.11. I want to use ValidFor in toolbar actions. Is it possible?

No it is not supported.

3.12. I want to turn the double click prevention off, how?

TVC has a built in logic to prevent memory leakage problems from double clicks in the category tree. The problem occurs as structure browser table beans are loaded into session but never removed as the forward to the jsp registering the onunload event is never rendered because of the new request.

If you have any problems with the functionality you can turn it off using the init parameter

tvc.structurebrowser.preventDblClickFromCategoryTree=false

4. Structure Browser Forms

4.1. We want to customize the look and post submit behavior of the TVC Form. Is there a possibility to add a custom FormRenderer?

The renderer of the whole form is not possible to customize right now, but it might be something we will consider to allow in the future

4.2. We want to define a custom forward as the form action create completes, how?

To make the form forward to your own jsp, you can specify a custom processor for the form, and override the getForward() method, which is responsible for specifying where to forward after the form has been processed. Add the element <Processor>JAVACLASS</Processor>, pointing to a java class extending in this case the CreateObject class, since it’s a create form, and implementing the getForward method.

4.3. Why doesn’t create and connect connect?

I’m creating “Create And Connect” Form but I have problems in it.

I was wondering if I’m able call TVC CreateAndConnect Form using Schema Command object? My problem is that it’s calling this form alright but for some reason it’s not connecting newly created object to object where call is made from.

_For some reason it seems that it’s not passing parent object id to CreateAndConnect Form. _

Maybe you’re just missing this:

<setting>
    <name>Submit OID</name>
    <value>true</value>
</setting>

4.4. I am using TVC create form and plan to use our custom Number Generator (neither TVC nor AEF). How can i do that?

TVC Forms have support for processors. A processor is what contains the main logic for whatever the result of the form should be. In the case of create forms, there is a processor used that simply creates objects and sets the attributes and basics for it.

If some special logic, such as a custom name generator, is needed when creating objects, it is possible to create your own form processor:

<Form>
    <FormProcessor>com.acme.MyProcessor</FormProcessor>
    ...
</Form>

The specified class must extend from the class com.technia.tvc.structurebrowser.form.process.FormProcessor.

Here is a simple example:

public class ExampleProcessor extends FormProcessor {
    public ExampleProcessor(Form fc) { super(fc); }

    @Override
    public List<String> perform(Form form) throws Exception {
        List<String> resultIds = new ArrayList<String>();
        // Create an object
        BusinessObject bo = BusinessObjectUtils.create(type,
            name, revision, basics.getVAULT(), basics.getPOLICY(),
            TxManager.getCurrentUser(), objectAttributeList);
        BusinessObjectUtils.setDescription(bo, basics.getDESCRIPTION());
        // Add the object id to the results list
        resultIds.add(bo.getObjectId());
        return resultIds;
    }
}

5. FAQ Graphic Reporting

5.1. Is drill down available for gvis charts?

No.

Also: We are not developing gvis charts any more so do not expect this in the future. Please use jqplot implementation instead as that is the api that we are adding functionality for.

6. FAQ Report Generator

6.1. What are those "Conversion Properties" really?

The name is legacy, and originates from TVC Report Generator 3.0 (2003).

The conversion properties is a multiline attribute on the report-definition object.

The original idea was that this attribute will hold properties/settings that controls the data-conversion, but the scope of this attribute has grown and is used for many purposes. Example:

  • Defining the name of the generated report:

    • Defining the file prefix of the generated report (file.prefix=ECO_Report)

    • Defining the file suffix of the generated report (file.suffix=pdf)

    • Defining the content-type of the generated report(file.contentType=application/pdf)

  • Whether or not to use FOP 0.20.5 or the latest FOP version (useLatestFOP=true|false) The default value for this can be specified globally for the report generator.

  • Whether or not to generate the report "on demand" (file.on.demand=true|false)

  • Whether or not to extract the data, which the report is based upon, as a super user (createAsSuperUser=true|false)

  • Override the converter, e.g. specifying a custom Java class (converterClass=com.acme.MyConverter)

    Must implement the interface com.technia.tvc.reportgenerator.Converter

  • Transaction type during dataextraction. In some rare cases, one will do some update to the database and that requires an update transaction to be started (transactionType=read|update|none)

  • Defining post processors (postProcessors=pdf-stamp,zip)

    • The post processors are invoked after the report has been created, but before any output handler is processed

  • Defining output handlers (outputHandlers=mail,checkin,custom)

    • The outout handler typically delivers the generated report somewhere

  • Specifying the name of the queue, in which the report will be produced (queue.name)

  • The report generator has a mechanism for distributing the creation of a report into one/several different processes in order to reduce load on the application servers. Specifying a pre-processor (*Note: this is not documented yet) that handles pre-processing when creating the report such as defining custom page to display (preProcessorClass=com.acme.MyPreProcessor)

    The pre processor must implement the interface com.technia.tvc.reportgenerator.preprocess.PreProcessor

6.2. Can I reuse my data-handlers in the Report Generator as well?

Yes.

The purpose with data handlers is to create "Cell" and populate these with value(s) (a Cell can have multiple CellValue’s associated). The report generator produces output according to what the cell’s on a row contains, and this typically looks like:

<cell>
    <value oid="..." rid="..." type="...">...</value>
    <value oid="..." rid="..." type="...">...</value>
</cell>

Note that a value in a cell can be associated with a different object, which in turn results in that the oid/rid/type attribute is added.

The value itself is escaped by default, as the value might contain characters that causes the XML data to be invalid. If you want to populate a cell with vaules that represents XML data, you can do this by applying the setting:

Preserve Output = TRUE

The value that is being added, is retrieved from the method "getDisplayValue" on the CellValue instance.

In many cases, it is very useful to implement a datahandler that produces XML data, for reference see Report Generator Data Handler Example on how to implement such a datahandler in the report generator.

6.3. How can I create Excel reports, without having to produce HTML that is opened in Excel

As usual, you have a number of alternatives to choose from:

  1. An alternative to creating HTML output, is to create XML reports that follows the SpreadsheetML format.

    1. For more information regarding SpreadsheetML, see this URL: SpreadsheetML @ MSDN

    2. In order to be able to produce SpreadsheetML, one need to make sure that the following properties are set on the report definition:

      Output Format = XML
      Displayed Output Format = Excel
      Stylesheet = <name of stylesheet that produces StylesheetML output>
    3. In addition, you probably have to play around with the so called "conversion properties"

      file.contentType=application/vnd.ms-excel (in order to force Excel to open the file)
  2. Implementing a custom report, that produced binary output with help from for example POI: POI @ Apache

    1. You need to implement a Java class that is found from this link: <Custom Report Example>

    2. Finally, you need to specify the name of the class within the report definition (of type TVC Custom Report)

6.4. How can I produce a report without having to bother about XML/XSLT

The original idea with the TVC Report Generator was to generate XML over a set of objects by using a table (or system table) and convert this XML into some other format using a so called converter. The most famous examples are:

Convert the raw XML to XSL-FO and use FOP to produce for example PDF from the XSL-FO

Convert the raw XML to HTML directly (either creating a HTML report, or a HTML page that Excel can interpret)

The good thing with XML/XSLT is that you can modularize the report and reuse pieces like tables, datahandlers, inquiries etc and only spend time on developing the stylesheets.

If you want to create reports without the influence of XML/XSLT, then you need to do slightly more coding than you otherwise would have needed. In some cases, the time of doing that is shorter than developing stylesheets but sometimes not.

Anyhow, what you are looking for is achieved by implementing a so called Custom Report, which uses a custom Java class for producing the report. Please look at the FAQ Custom Report Example for details.

Again, this approach requires you to implement data-extraction etc. Of course, you can utilize the TVC API to load inquiries, performing expansions and evaluate a table over a flat-list or structure.

An alternative, which somehow requires you to parse XML, is to use a custom converter.

converterClass=com.acme.MyConverter

This class should implement this interface:

com.technia.tvc.reportgenerator.Converter

It has one method that needs to be implemented, and some skeleton code is shown below:

public void convert(ConverterCtx ctx) throws IOException {
    InputStream in == ctx.getInput();

    OutputStream out == ctx.getOutput();

    Report report == ctx.getReport();

    // Read XML data from the input stream

    // Do whatever you need with this data,

    // and write the generated report to the outputstream

    // You can from the Report instance get settings/properties // defined
    in there.
}

Depending on what output you create, you need to set this on the report as well:

file.contentType=application/vnd.ms-excel file.prefix=report
file.suffix=.xls

6.5. How can I use my own custom logic for data grouping?

What you can do here, if you need more advanced logic for creating the groups, is to create a column with a datahandler in the table used for the report.

Include the grouping/formatting logic in this column so that the result is the grouping you need. Then use that column to group, and just hide it from the rest of the report (in the stylesheet, just skip that column).

6.6. How can I programatically create the XML?

You can use the Custom report. Depending on what output you want, you need to specify what converter to be used.

This example assumes that you will produce XSl-FO with your stylesheet and use a compatible output format (PDF for example):

import com.technia.tvc.core.TVCException;
import com.technia.tvc.core.html.io.XMLWriter;
import com.technia.tvc.reportgenerator.Converter;
import com.technia.tvc.reportgenerator.DataExtractor;
import com.technia.tvc.reportgenerator.DataExtractorCtx;
import com.technia.tvc.reportgenerator.convert.FOConverter;
import com.technia.tvc.reportgenerator.impl.CustomReport;
import java.io.IOException;

public class ExampleWithFOConversion extends CustomReport implements DataExtractor {
    /**
     * Don't forget this field if you want to run this report distributed
     */
    private static final long serialVersionUID == 1L;

    @Override
    public DataExtractor getDataExtractor() {
        return this;
    }

    public void extract(DataExtractorCtx ctx) throws TVCException, IOException {
        XMLWriter writer == ctx.getXMLWriter();
            /*
             * Construct your XML data here through the XMLWriter
             */
        writer.startElement("my-root")
            .startElement("sub")
            .addText("text")
            .endElement()
            .startElement("next-sub")
            .addAttribute("foo", "bar")
            .addText("hello world")
            .endElement()
            .finish();

    }

    @Override public Converter getConverter() {
        return FOConverter.getInstance();
    }
}

6.7. How can I use for example IText to create PDF within the Report Generator?

Again, use the Custom Report as base. IText is part of the TVC-Core, so you don’t need any additional JARs for this.

See this example:

import com.technia.tvc.core.TVCException;
import com.technia.tvc.core.util.pdf.PDFPageSize;
import com.technia.tvc.reportgenerator.DataExtractor;
import com.technia.tvc.reportgenerator.DataExtractorCtx;
import com.technia.tvc.reportgenerator.impl.CustomReport;
import com.technia.tvc.lowagie.text.Document;
import com.technia.tvc.lowagie.text.DocumentException;
import com.technia.tvc.lowagie.text.Paragraph;
import com.technia.tvc.lowagie.text.pdf.PdfWriter;
import java.io.IOException;

public class ExampleWithIText extends CustomReport implements DataExtractor {

    /**
     * Don't forget this field if you want to run this report distributed
     */
     private static final long serialVersionUID == 1L;

    public void extract(DataExtractorCtx ctx) throws TVCException, IOException {
        try {
            extractImpl(ctx);
        } catch (DocumentException de) {
            throw new TVCException("unable to create pdf document", de);
        }
    }
}

    protected void extractImpl(DataExtractorCtx ctx) throws DocumentException, IOException {
        Document iTextDocument == new Document(PDFPageSize.LETTER.size());
        /* PdfWriter writer == */PdfWriter.getInstance(iTextDocument, ctx.getOutputStream());
        iTextDocument.open();
        iTextDocument.newPage();
        iTextDocument.add(new Paragraph("Hello World"));
        iTextDocument.close();
    }

    @Override
    public DataExtractor getDataExtractor() {
        return this;
    }
}

6.8. How do I execute a report from mql?

You need to point out the webapp directory using the environment variable TVC_WEBAPP_DIR

set TVC_WEBAPP_DIR=<webapp directory goes here>
MQL<1>set context user creator

MQL<2>execute program TVCReportGenerator -method mxMain -oid=<object id goes here> -report=tvc:report:..../MyConf.xml

6.9. XSLT

6.9.1. Malformed Documents

The most common error with the report generator is malformed XSLT/XML definitions. If you don’t have a good XML editor, these can sometimes be very frustrating and time consuming.

While a good editor is recommended there are always exceptions (even Eclipse sometimes chokes if you have a really bad mistake) where you just need a quick way of finding what is causing the error. The one trick that seems to be the quickest is to rename the XSLT to XML and open up in Microsoft Internet Explorer: IE will tell you exactly what is wrong and on what line.

Another great option is to simply copy your XML or XSLT into the W3C schools validator located at http://www.w3schools.com/xml/xml_valid http://www.w3schools.com/xml/xml_validator.asp[ator.asp]

6.9.2. Could not the translet class (GregorSamsa)

Who is Gregor and why is he causing so many issues with my stylesheet? This is actually a limitation of the Sun XSLTC as it cannot handle a stylesheet over 64kb - yes, this could be a frustrating limit but then again your stylesheets should never get this large. To fix this issue, you will need to modularize your stylesheet and break it up into smaller files and/or templates instead of just one bit stylesheet

6.9.3. Corrupt File (15bytes) on Websphere/AIX with no errors on TVC Console

In most cases, errors that cause a corrupt 15 byte file can be found simply by turning TVC Debug On which then shows a more verbose message that typically shows you the stylesheet error that is causing the problem. However, on Websphere/AIX this may not always be true so you should also take a look at the system error log file.

One such error found recently is that if the xsl:sort is invalid (e.g. uses data-type="string" instead of data-type="text") then it causes the stylesheet to fail with no warning but the websphere error log file will show the message of "The string 'string' was used where a QName that has a prefix is required."

6.10. Custom Report Example

Skeleton class for custom reports.

public class Example extends CustomReport implements DataExtractor, Converter {
    private static final long serialVersionUID = 1L;

    public DataExtractor getDataExtractor() {
        return this;
    }

    public void extract(DataExtractorCtx ctx) throws TVCException, IOException {
        /*
         * Get a reference to the object, which the report is being created for
         */
        ObjectRef ref = ctx.getReport().getSourceObject();
        ...
        /*
         * If you generate binary data; obtain the output stream here
         */
        OutputStream out = ctx.getOutputStream();
        ...
    }

    public Converter getConverter() {
        /*
         * If the data uses a converter, return it here.
         * If not; simply return null.
         */
        return this;
    }

    public void convert(ConverterCtx ctx) throws IOException {
        // If you decide to implement the Converter interface, you need to do something here...
    }
}

6.11. Report Generator Data Handler Example

This datahandler already exists in TVC Report Generator; so you don’t have to compile this on your own. The class is here for reference only.

The name of the class is com.technia.tvc.reportgenerator.datahandler.AttributesHandler

import com.technia.tvc.core.db.AttributeUtils;
import com.technia.tvc.core.db.DateUtils;
import com.technia.tvc.core.db.aef.AEFUtils;
import com.technia.tvc.core.db.model.AttributeConstants;
import com.technia.tvc.core.db.model.AttributeInfo;
import com.technia.tvc.core.db.model.RelationshipInfo;
import com.technia.tvc.core.db.model.TypeInfo;
import com.technia.tvc.core.db.select.Statement;
import com.technia.tvc.core.db.table.evaluator.DataHandler;
import com.technia.tvc.core.db.table.evaluator.EvaluatedData;
import com.technia.tvc.core.db.table.evaluator.EvaluationInput;
import com.technia.tvc.core.db.table.evaluator.SelectedData;
import com.technia.tvc.core.gui.table.Cell;
import com.technia.tvc.core.gui.table.Column;
import com.technia.tvc.core.gui.table.impl.StringCell;
import com.technia.tvc.core.html.io.XMLWriter;
import com.technia.tvc.core.html.io.XMLWriterFactory;
import com.technia.tvc.core.util.StringUtils;

import java.io.StringWriter;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

/**
 * This handler can be used to retreive all attributes/values for a relationship
 * or object, and output the data in the cell as XML.
 * <p>
 * The generated XML has the following format:
 *
 *
 *  &lt;attributes&gt;
 *      &lt;attribute name=&quot;...&quot; type=&quot;...&quot; localizedName=&quot;...&quot;&gt;...&lt;/Attribute&gt;
 *      &lt;attribute name=&quot;...&quot; type=&quot;...&quot; localizedName=&quot;...&quot;&gt;...&lt;/Attribute&gt;
 *      ...
 *  &lt;/attributes&gt;
 */
public class AttributesHandler implements DataHandler {

    public void prepareEvaluation(Column col, EvaluationInput input) {
        if (col.usesBusinessObject()) {
            input.addSelectBus(Statement.TYPE);
            input.addSelectBus(Statement.ATTRIBUTE_VALUE);
        } else {
            input.addSelectRel(Statement.TYPE);
            input.addSelectRel(Statement.ATTRIBUTE_VALUE);
        }
    }

    public Cell createCell(Column col, EvaluatedData data) {
        return new StringCell(col);
    }

    public void populateCell(Cell cell, EvaluatedData data) {
        boolean bus = cell.getColumn().usesBusinessObject();
        SelectedData sd = bus ? data.getObjectData() : data.getRelationshipData();
        List<String> attributes = null;
        String typeName = sd.getSelectValue(Statement.TYPE);
        if (!StringUtils.isOnlyWhitespaceOrEmpty(typeName)) {
            try {
                if (bus) {
                    attributes = TypeInfo.getInstance(typeName).getAttributeNames();
                } else {
                    attributes = RelationshipInfo.getInstance(typeName).getAttributeNames();
                }
            } catch (Exception shouldNeverHappenNormally) {
            }
        }
        if (attributes != null) {
            StringWriter sw = new StringWriter();
            XMLWriter xml = XMLWriterFactory.newWriter(sw);
            xml.startElement("attributes");
            String name, value, localizedName;
            int type = AttributeConstants.TYPE_UNKNOWN;
            Locale locale = cell.getColumn().getLocale();
            for (Iterator<String> itr = attributes.iterator(); itr.hasNext();) {
                name = itr.next();
                value = sd.getSelectValue("attribute[" + name + "].value", true);
                if (value != null) {
                    xml.startElement("attribute");
                    try {
                        AttributeInfo ai = AttributeInfo.getInstance(name);
                        type = ai.getType();
                        if (type == AttributeConstants.TYPE_DATETIME) {
                            if (!StringUtils.isOnlyWhitespaceOrEmpty(value)) {
                                Date d = DateUtils.parse(value);
                                xml.addAttribute("isoDateTime", DateUtils.formatISO8601DateTime(d));
                                xml.addAttribute("isoDate", DateUtils.formatISO8601Date(d));
                                value = DateUtils.formatForDisplay(d, locale);
                            }
                        }
                    } catch (Throwable t) {
                    }
                    xml.addAttribute("type", AttributeUtils.toString(type));
                    xml.addAttribute("name", name);
                    localizedName = AEFUtils.getLocalizedAttributeName(name, cell.getColumn()
                        .getLocale());
                    if (StringUtils.isOnlyWhitespaceOrEmpty(localizedName)) {
                        localizedName = name;
                    }
                    xml.addAttribute("localizedName", localizedName);
                    xml.addText(value);
                    xml.endElement();
                }
            }
            xml.finish();
            cell.addValue(sw.toString());
        }
    }
}

7. Grid Browser

8. XBOM

8.1. How do I override the default access of XBL?

8.1.1. Alt.1

Implement a custom handler

public class Example extends Handler {
    @Override
    public TableBean<? extends TableData> create(HandlerCtx ctx) throws TVCException {
        TableBean<?> t = DefaultHandler.getInstance().create(ctx);
        for (TableData d : IteratorUtils.toList(t.getTableData())) {
            for (Cell c : IteratorUtils.toList(d.getRow().getCells())) {
                c.setEditable(true);
            }
        }
        return t;
    }
}

8.1.2. Alt.2

Implement a datahandler for specific cell access

public class EditableDataHandler extends DefaultDataHandler {
    @Override
    public void populateCell(Cell cell, EvaluatedData data) {
        super.populateCell(cell, data);
        cell.setEditable(true);
    }
}

8.2. Can I synchronize data between comparison results?

The synchronization feature is there, but not on XBL type baselines, only on the original XBOM, i e manufacturing or engineering baselines.

9. File Manager

9.1. I have created a custom jsp page to run TVC standalone and file manager does not work?

Add the following tag to your "main page"

<body>
<%@include file="/tvc/office/tvcOfficeObjectTag.jspf"%> ..

10. Personal Browser

11. Mobile

12. Wiki

13. TVX

13.1. Where can I find the source code?

It is included inside the jar file. (You can open the jar file using 7zip)