Ab Version 4 unterstützen die InDesign® Comet Plug-Ins Datenverbindungen mit dem priint PublishingServer. Einige in früheren Versionen projektspezifisch gelöste Anforderungen sind nun standardisiert.

Die gute Nachricht: Sie können mit comet 4 und dem PublishingServer - bis auf wenige Ausnahmen - ganz genau so weiter arbeiten wie bisher.

Die zweite gute Nachricht: einige Dinge sind jetzt sehr viel leichter umsetzbar.

Die dritte Nachricht betrifft den Rasteraufbau für Produkte:

Mit Comet 3 wurde vor nunmehr zwölf Jahren der Rasteraufbau durch den Seitenaufbau abgelöst. Der Rasteraufbau wurde seither unverändert weiter unterstützt aber nicht mehr weiterentwickelt. Mit Comet4 sind alle Paletten, die für die Konfiguration des Rasteraufbaus nötig waren (Raster, Rasterassistent, Aufbauregeln), entfernt wurden. Wir sind uns sicher, dass eine sechsjährige Umstellungsphase auf den Seitenaufbau ausreichend gewesen ist. Bereits konfigurierte Rasteraufbauten können, so wie sie sind, trotzdem immer noch verwendet werden, aber Bugfixing und Support für den Rasteraufbau sind eingestellt

Die folgenden Beschreibungen gelten, soweit nicht anders vermerkt, ausschließlich bei Datenverbindungen zu PublishingServern. Andere Datenverbindungen werden unverändert unterstützt.

Neues, Änderungen und Einschränkungen im Überblick:

Im PublishingServer-Umfeld enthält die StringID alle zur Bestimmung der Hierarchie und des Kontexts benötigten Informationen. Die numerischen IDs ID, ID2 sowie ID3 werden in der Regel nicht benötigt, aber ID muss aus Validitätsgründen einen Wert ungleich 0 haben und wird daher in der Regel auf 1 gesetzt.

Die StringID ist im PublishingServer-Umfeld folgendermaßen (und ohne die nur zur besseren Lesbarkeit eingefügten Zeilentrenner) aufgebaut:

 recordId
#groupId
#entityId
#entityClass
#parentRecordId
#parentGroupId
#parentEntityId
#parentEntityClass

Zur Bedeutung der einzelnen Elemente siehe die PublishingServer Dokumentation des EntityManagers bzw. Entitätenmodells.

In Platzhalterskripten kann auf einzelne Bestandteile der StringID mittels der folgenden Tags, Umgebungsvariablen und/oder cScript-Funktionen zugegriffen werden:

Tag Variable Funktion Beschreibung
<Record.Id> gPSRecordId idtype::record_id Id des Datensatzes
<Record.GroupId> gPSGroupId idtype::group_id Gruppen-Id des Datensazues
<Entity.Id> gPSEntityId idtype::entity_id Identifier der Entität
<Entity.Class> gPSEntityClass idtype::entity_class Klasse der Entität
<Record.ParentId> gPSParentRecordId idtype::parent_record_id Id des Parent-Datensatzes
<Record.ParentGroupId> gPSParentGroupId idtype::parent_group_id Gruppen-Id des Parent-Datensatzes
<Entity.ParentId> gPSParentEntityId idtype::parent_entity_id Identifier der Entität des Parents
<Entity.ParentClass> gPSParentEntityClass idtype::parent_entity_class Klasse der Entität des Parents

In TabellenInsert Methoden werden zudem folgende Tags und/oder Umgebungsvariablen definiert:

Tag Variable Beschreibung
<RootTableRecord.Id>gPSRootTableRecordIdId des Datensatzes der Tabelle
<RootTableRecord.GroupId>gPSRootTableGroupIdGroup Id des Datensatzes der Tabelle
<RootTableEntity.Id>gPSRootTableEntityIdIdentifier der Entität der Tabelle
<RootTableEntity.Class>gPSRootTableEntityClassKlasse der Entität der Tabelle
<RootTableRecord.ParentId>gPSRootTableParentRecordIdId des Parent-Datensatzes der Tabelle
<RootTableRecord.ParentGroupId>gPSRootTableParentGroupIdGroup Id des Parent Datensatzes der Tabelle
<RootTableEntity.ParentId>gPSRootTableParentEntityIdIdentifier der Entität des Parents der Tabelle
<RootTableEntity.ParentClass>gPSRootTableParentEntityClassKlasse der Entität des Parents der Tabelle
<ColumnRecord.Id>gPSColumnRecordIdId des Datensatzes der Spalte
<ColumnRecord.GroupId>gPSColumnGroupIdGroup Id des Datensatzes der Spalte
<ColumnEntity.Id>gPSColumnEntityIdIdentifier der Entität der Spalte
<ColumnEntity.Class>gPSColumnEntityClassKlasse der Entität der Spalte
<ColumnRecord.ParentId>gPSColumnParentRecordIdId des Parent-Datensatzes der Spalte
<ColumnRecord.ParentGroupId>gPSColumnParentGroupIdGroup Id des Parent Datensatzes der Spalte
<ColumnEntity.ParentId>gPSColumnParentEntityIdIdentifier der Entität des Parents der Spalte
<ColumnEntity.ParentClass>gPSColumnParentEntityClassKlasse der Entität des Parents der Spalte
<RowRecord.Id>gPSRowRecordIdId des Datensatzes der Zeile
<RowRecord.GroupId>gPSRowGroupIdGroup Id des Datensatzes der Zeile
<RowEntity.Id>gPSRowEntityIdIdentifier der Entität der Zeile
<RowEntity.Class>gPSRowEntityClassKlasse der Entität der Zeile
<RowRecord.ParentId>gPSRowParentRecordIdId des Parent-Datensatzes der Zeile
<RowRecord.ParentGroupId>gPSRowParentGroupIdGroup Id des Parent Datensatzes der Zeile
<RowEntity.ParentId>gPSRowParentEntityIdIdentifier der Entität des Parents der Zeile
<RowEntity.ParentClass>gPSRowParentEntityClassKlasse der Entität des Parents der Zeile
<CellRecord.Id>gPSCellRecordIdId des Datensatzes der Zelle
<CellRecord.GroupId>gPSCellGroupIdGroup Id des Datensatzes der Zelle
<CellEntity.Id>gPSCellEntityIdIdentifier der Entität der Zelle
<CellEntity.Class>gPSCellEntityClassKlasse der Entität der Zelle
<CellRecord.ParentId>gPSCellParentRecordIdId des Parent-Datensatzes der Zelle
<CellRecord.ParentGroupId>gPSCellParentGroupIdGroup Id des Parent Datensatzes der Zelle
<CellEntity.ParentId>gPSCellParentEntityIdIdentifier der Entität des Parents der Zelle
<CellEntity.ParentClass>gPSCellParentEntityClassKlasse der Entität des Parents der Zelle

Daneben werden in allen Umgebungen zwei neue Tags unterstützt:

Zur Modularisierung von cscripten oder Wiederverwendung eigener cscript Funktionen können in Ison Skript-Bibliotheken erstellt werden. Nähere Informationen dazu im priint:ison Benutzerhandbuch.
Diese Bibliotheken werden mit einem eindeutigen Identifier versehen, über den sie in cscript eingebunden werden können:

#include "[pubserver]/Identifier.h"

Methoden Ihrer (Server) Java Plugins können über Anweisung nach folgendem Schema in cscript verwendet werden:

#include "[pubserver]/plugin/Plugin-mapped-name.c"

Dokumentierte Header der in cscript verfügbaren Methoden eines Java PlugIns liefert dieser Aufruf (Achtung! Dieser Code dient nur dokumentativen Zwecken, er kann in cscript nicht interpretiert werden):

#include "[pubserver]/plugin/Plugin-mapped-name.h"

Die Methoden aller Plugins können so eingebunden werden:

#include "[pubserver]/plugins.c"

Bzw. auch hier die Ausgabe dokumentierter Funktions-Deklarationen:

#include "[pubserver]/plugins.h"

Schließlich noch die Include-Anweisung für die CScriptStandardLibrary:

#include "[pubserver]/stdlib.c"
// Shortcut for: #include "[pubserver]/plugin/com.priint.pubserver.comet.bridge.cscript.CScriptStandardLibrary.c"

Bzw. deren kommentierter Funktions-Signaturen:

#include "[pubserver]/stdlib.h"
// Shortcut for: #include "[pubserver]/plugin/com.priint.pubserver.comet.bridge.cscript.CScriptStandardLibrary.h"
Mehr hierzu siehe in Abschnitt Aufruf eigener Java Plugins.

Eine Reihe neuer cscript-Funktionen sind vor allem im PublishingServer Umfeld sinnvoll und im jeweiligen Modul ausführlich dokumentiert:

Platzhalter werden im PublishingServer Umfeld ausschließlich über priint:ison konfiguriert. Der Datenzugriff erfolgt über - ebenfalls in ison konfigurierte - DataProvider.

Ausführliche Informationen hierzu finden sich in der PublishingServer Dokumentation, an dieser Stelle nur so viel: Ein DataProvider erfüllt 2 Aufgaben, nämlich

Für beide Aufgaben werden mit dem PublishingServer schon eine Reihe fertiger Implementierungen mitgeliefert, eigene Methoden können bei Bedarf einfach als Java Plugin entwickelt und hinzugefügt werden.

Ein Platzhalter kann zudem noch Methoden zur weiteren Datenaufbereitung definieren. Auch hier wird bereits ein breites Spektrum mit dem PublishingServer mitgeliefert, weitere können als Java Plugin selbst bereitgestellt werden.

Es sollte also eher selten notwendig sein, weitere Datenaufbereitung in cscript zu implementieren (ggf. lohnt sich vor einer solchen Entscheidung auch ein Blick in die Gestaltungsregeln). Falls doch, kann die Standard-Laden Methode des Platzhalters über die cscript Funktion

server::load_placeholder_str

aufgerufen werden. Ausführliche Dokumentation und Beispiele finden Sie hier.

Beispiel: Laden eines Platzhalters

Dieses Skript hat überhaupt keine Auswirkung, es lädt einfach den Text über die auf dem Server konfigurierte Zugriffsmethode inklusive aller Konvertierungen und Bearbeitungen und setzt den Text am Ende in den Platzhalter ein - genau dasselbe Ergebnis also, wie es ohne Skript zu erwarten wäre. Um ihm dennoch einen gewissen Sinn zu geben, schreiben wir den vom Server erhaltenen Text vorher in die Logdatei:

int main ()
{
	String		str 	= string::alloc();
	int			result 	= server::load_placeholder_str(str);

	wtlog("", "load_placeholder_str result=%d, text='%s'\n", result, str);

	if (result == 0)
	{
		textmodel::replace(str);
	}

	string::release(str);
	return result;
}

Beispiel 2: Überschreiben von Parametern

Als 3. bis nter Parameter können Key-Value Paare angegeben werden. Sinnvolle Keys sind die Namen aller PublishingServer spezifischen Tags, also zum Beispiel Record.Id, Entity.Id, Entity.ContextLanguage usw.

Damit ist es möglich, Platzhalter "umzubiegen" und z.B. einen (irgendwie client-seitig zu ermittelnden) Kontext anzugeben. Ob das sinnvoll ist und sich nicht besser durch Konfiguration einer geeigneten Kontext-Regel für den Platzhalter erledigen ließe, steht auf einem anderen Blatt...

int main ()
{
	String 		str 	= string::alloc ();
	int			result 	= server::load_placeholder_str(
							str,
							"Entity.ContextLanguage", "eng",
							"Model.Id", "Anderes_Datenmodell");
	
	wtlog("", "load_placeholder_str result=%d, text='%s'\n", result, str);
	
	if (result == 0)
	{
		textmodel::replace(str);
	}
	
	string::release(str);
	return result;
}

Diese Informationen gelten für den klassischen Tabellenaufbau, daneben gibt es im PublishingServer auch die Möglichkeit, Tabellen Server-seitig zu generieren. Welche der Möglichkeiten die jeweils geeignetere ist, hängt sicher vom Anwendungsfall ab und soll an dieser Stelle nicht weiter thematisiert werden.

Bei der Client-seitigen, also klassischen, Generierung wird für Spalten, Zeilen oder einzelne Zellen hinterlegt, mit welcher Methode Produkt- oder Artikel-IDs für den Aufbau der Tabelle ermittelt werden. Dies sind sogenannte TableInsert-Methoden, die ebenfalls über priint:ison angelegt werden können. Das Prinzip ist ganz ähnlich dem von Platzhaltern, auch hier werden die Daten über einen DataProvider geladen, der zugleich für die Transformation in eine geeignete Struktur zuständig ist - mit 2 Unterschieden allerdings:

Mehr Informationen zum TableInsert Methoden finden Sie hier.

In den eher seltenen Fällen, in denen die IDs in einem eigenen cscript ermittelt werden müssen, können Sie auf folgende Weise auf die Standard-Laden Funktion der TableInsert Methode zugreifen:

server::load_table_ids(gProducts, gMoreGroups)

Ausführliche Dokumentation und Beispiele finden Sie hier.

Beispiel: das denkbar einfachste TableInsert Skript

Dieses Skript verhält sich "neutral", Ergebnis ist also genau dasselbe, wie wenn direkt die für die Spalte, Zeile oder Zelle konfigurierte Methode ausgeführt würde:

int main ()
{
	return server::load_table_ids (gProducts, gMoreGroups);
}

Wie bei der server::load_placeholder_str Funktion können auch hier durch Key-Value Paare als 3 .. nter Parameter Werte überschrieben werden.

Bitte beachten Sie
Von der Verwendung der server::dataprovider_load Funktion wird allgemein abgeraten. Eine wesentlich einfachere und sicherere Lösung ist - je nach Aufruf-Kontext - In der Skript-Dokumentation der Funktion ist ausführlich dargelegt, warum sich die Verwendung einer Alternative empfiehlt bzw. warum von server::dataprovider_load abgeraten wird.

Auf ähnliche Weise wie Platzhalter oder Tabellen können Sie auch (fast) beliebige DataProvider in beliebiger Skriptumgebung laden. Beachten Sie, dass Sie dann alle erforderlichen Werte (die normalerweise aus dem Platzhalter- oder Tabellenkontext automatisch übernommen werden) von "Hand" setzen müssen, also als KeyValue-Paare der Funktion als übergeben.

Beachten Sie weiterhin:

Ausführliche Dokumentation und Beispiele finden Sie hier.

server::dataprovider_load()

Beispiel: Füllen einer IDTypeListe

int main ()
{
	IDTypeList	ids 	= idtypelist::alloc();
	int			result 	= 0;
	int			index	= 0;
result = server::dataprovider_load( ids, "ChildBuckets", 0, 0, "Record.Id", "<Record.Id>"); if (result == 0) { // copy ids to the global IDTypeList gProducts // (will only work this way, if executed as a TableInsert method) for (index = 0; index < linklist::length(ids); ++index) { idtypelist::insert(gProducts, -1, idtypelist::get(ids, index); } } // clear list, but do not clear entries idtypelist::clear(ids, 0); return result; }

Beispiel: Holen eines einfachen Strings

int main ()
{
	char	* 	value 	= alloc(32768);
	int			result 	= 0;
	
	result = server::dataprovider_load(
				value,
				"FirstText",
				0, 0, "Record.Id", "<Record.Id>",
				"Entity.ContextLanguage", "deu");
	
	if (result == 0)
	{
		textmodel::replace(value);
	}
	
	release(value);
	return result;
}

Hierfür ist die Installation des Java Server Plugins CometTableOfContents erforderlich.

Dieses Plugin stellt spezielle DataQuery Methoden bereit, die in Verbindung mit einem entsprechend konfigurierten DataProvider und einem Text-Platzhalter der Entität Table Of Contents den Zugriff auf Inhaltsverzeichnisdaten in Ihrem InDesign® oder PDF Dokument erlauben. Zur Konfiguration des Datenzugriffs siehe Dokumentation der priint:ison Anwendung.

Angelegt werden Verzeichniseinträge einfach durch Aufruf der cscript Funktion

    linklist::insert_toc_entry()

Beispiel: Anlegen von Verzeichniseinträgen eines bestimmten Platzhalters

#include "internal/types.h"

int main ()
{
	LinkList	placeholders 	= linklist::alloc(1);
	int			result;

	linklist::insert(placeholders, 67301234);
	result = linklist::insert_toc_entry(
				placeholders,
				kDesignateDocument,
				"myPublication", 
				"12345");
	linklist::release(placeholders);

	return result;
}

Java Methoden eines PubServer Plugins können in cscript aufgerufen werden. Dafür müssen ein paar Voraussetzungen erfüllt sein:

Belohnt werden diese (sehr überschaubaren) Mühen durch eine fast nahtlose Integration von Java-Funktionalitäten in cscript.

Beispiel 1 - Hello

Das Grundprinzip erklärt sich am besten durch ein erstes Beispiel (Grundkenntnisse in der PubServer Java Plugin Erstellung und cscript Programmierung werden vorausgesetzt):

@Stateless(mappedName=HelloWorld.MAPPED_NAME)
@LocalBean
@PubServerPlugin
public class HelloWorld extends PluginControlDefault {
	
	public static final String MAPPED_NAME = "com.priint.pubserver.comet.cscript.HelloWorld";
	
	/**
	 * Hello World
	 * 
	 * @return Hello World
	 */
	@PubServerMethod(type=PluginMethod.MethodType.GENERIC)
	@CometCScriptFunction
	public String helloWorld() {
		return "Hello World";
	}
}   
Der zugehörige cscript-Code zum Aufruf dieser Methode:
#include "[pubserver]/plugin/com.priint.pubserver.comet.cscript.HelloWorld.c"
     
int main() 
{
    char 	* 	message 	= helloWorld();
    
    showmessage ("Server said: %s", message);
    
    release(message);
    return 0;
}

Beispiel 2 - Parameter

Ein zweites Beispiel zeigt, wie der Methode Parameter übergeben werden können:

@Stateless(mappedName=HelloWorld.MAPPED_NAME)
@LocalBean
@PubServerPlugin
public class HelloWorld extends PluginControlDefault {
	
	public static final String MAPPED_NAME = "com.priint.pubserver.comet.cscript.HelloWorld";
	/**
	 * Hello World
	 * 
	 * @return Hello World
	 */
	@PubServerMethod(type=PluginMethod.MethodType.GENERIC)
	@CometCScriptFunction
	public String helloWorld2(@PubServerMethodParameter String login) {
		return "Hello " + login + "!";
	}
}   
Und der zugehörige cscript-Code:
#include "[pubserver]/plugin/com.priint.pubserver.comet.cscript.HelloWorld.c"

int main() 
{
    char 	* 	login   	= alloc(4096);
    char 	* 	message 	= 0;
    
    login   = system::login(login);
    message = helloWorld2(login);
    
    showmessage("Server said: %s", message);
    
    release(message);
    release(login);
    
    return 0;
}

Anhand dieser Beispiele lässt sich festhalten:

und und weiterhin

Weiteres Basisinformationen

 

Das in der Ison Entwicklungsumgebung enthaltene Beispiel-Plugin-Projekt DemoCScript enthält noch viele weitere Beispiele und nützliche Informationen.

Die Sprachmittel von Java und cscript unterscheiden sich - bei aller Ähnlichkeit der Syntax - doch etwas:

Für die cscript / Java Schnittstelle können Sie für jede Methode festlegen, ob der zugehörige cscript Aufruf als "Funktion" oder als "Prozedur" ausgeführt werden soll, unabhängig davon, ob die Methode einen Wert zurück liefert oder nicht. Dies wird mit dem Attribut callStyle der @CometCScriptFunction Annotation angegeben; folgende zwei Werte sind möglich:

Wenn Sie CallStyle.PROCEDURE für eine Methode mit Rückgabewert verwenden, wird für diesen Rückgabewert eine zusätzliche out Variable der Parameterliste der cscript-Funktion vorangestellt. Siehe hierzu das folgende 3. Beispiel.

Beispiel 1 - "Funktion"

@Stateless(mappedName=HelloWorld.MAPPED_NAME)
@LocalBean
@PubServerPlugin
public class HelloWorld extends PluginControlDefault {

	@PubServerMethod(type=PluginMethod.MethodType.GENERIC)
	@CometCScriptFunction(callStyle=CallStyle.FUNCTION /* = default! */ )
	public int max(
			@PubServerMethodParameter(name="n1") int n1, 
			@PubServerMethodParameter(name="n2") int n2) {
		return n1 > n2 ? n1 : n2;
	}
}   
Und die zugehörige cscript-Funktion und Aufrufbeispiel:
// Funktions-Signatur
int max(int n1, int n2);

// Beispiel-Aufruf
int n = max(17, 23);

Beispiel 2 - "Prozedur"

@Stateless(mappedName=HelloWorld.MAPPED_NAME)
@LocalBean
@PubServerPlugin
public class HelloWorld extends PluginControlDefault {

	@PubServerMethod(type=PluginMethod.MethodType.GENERIC)
	@CometCScriptFunction(callStyle=CallStyle.PROCEDURE)
	public void sendEmail(
			@PubServerMethodParameter(name="recipient") String recipient) throws CometException {
		try {
		 	deliverEmail(recipient);
		}
		catch (Exception e) {
			int errorCode = 13;
			throw new CometException(errorCode, "Could not deliver Email, reason: " + e.getMessage(), e);
		}
	}
}   
Und die zugehörige cscript-Funktion und Aufrufbeispiel:
// Funktions-Signatur
int sendEmail(char* recipient);

// Beispiel-Aufruf
int errorCode = sendEmail("support@priint.com");

Beispiel 3 - "Prozedur mit Rückgabewert"

@Stateless(mappedName=HelloWorld.MAPPED_NAME)
@LocalBean
@PubServerPlugin
public class HelloWorld extends PluginControlDefault {

	@PubServerMethod(type=PluginMethod.MethodType.GENERIC)
	@CometCScriptFunction(callStyle=CallStyle.PROCEDURE)
	public String sendEmail(
			@PubServerMethodParameter(name="recipient") String recipient) throws CometException {
		try {
		 	deliverEmail(recipient);
			String status = getMailDeliveryStatus();
			return status;
		}
		catch (Exception e) {
			int errorCode = 13;
			throw new CometException(errorCode, "Could not deliver Email, reason: " + e.getMessage(), e);
		}
	}
}   
Und die zugehörige cscript-Funktion und Aufrufbeispiel:
// Funktions-Signatur
// Für den String-Rückgabewert der Prozedur wird ein zusätzlicher 
// Parameter (char** out) definiert, Erläuterung siehe oben.
int sendEmail(char** out, char* recipient);

// Beispiel-Aufruf
char* status = 0;

// zu beachten: der Adress-Operator beim folgenden Aufruf, es
// wird die Speicheradresse der String-Adresse übergeben.
// Bei erfolgreicher Ausführung zeigt status nach Aufruf auf 
// eine gültige String-Adresse, bei Fehlern weiterhin auf 0.
int errorCode = sendEmail(&status, "support@priint.com");

if (errorCode == 0) {
	wlog("", "Sending mail succeeded, current status: %s\n", status);
}
else {
	wlog("", "Sending mail failed with error code '%d'\n", errorCode);
}
if (status != 0) {
	release(status);
}

Beispiel 4 - Fehlerbehandlung bei Funktionen

Sofern nicht anders angegeben, wird bei Auftreten irgendeines Fehlers beim Aufruf einer cscript Funktion

zurückgegeben.

Soll im Fehlerfalle ein anderer Wert zurückgegeben werden, können Sie dies mittels des Attributs failureValue der @CometCScriptFunction Annotation festlegen.

Zu Beachten:

@Stateless(mappedName=HelloWorld.MAPPED_NAME)
@LocalBean
@PubServerPlugin
public class HelloWorld extends PluginControlDefault {
	
	public static final String MAPPED_NAME = "com.priint.pubserver.comet.cscript.HelloWorld";
	/**
	 * Hello World
	 * 
	 * @return Hello World
	 */
	@PubServerMethod(type=PluginMethod.MethodType.GENERIC)
	@CometCScriptFunction(failureValue="You are not welcome. Goodbye.")
	public String helloWorld3(@PubServerMethodParameter String login) throws PubServerException {
		if (login.equals("me")) {
		    return "Hello " + login + "!";
		} 
		else {
			throw new AuthenticationFailureException();
		}
	}
}   
Und wieder der zugehörige cscript-Code:
#include "[pubserver]/plugin/com.priint.pubserver.comet.cscript.HelloWorld.c"

int main() 
{
    char 	* 	login   	= alloc(4096);
    char 	* 	message 	= 0;
    int 		result     = 0;
    
    login   	= system::login(login);
    message 	= helloWorld3(login);

    // In der Praxis sollten Sie den Rückgabewert trotzdem auf 0 prüfen... sicherheitshalber.
    if (strcmp(message, "You are not welcome. Goodbye.") == 0) 
    {
		showmessage("Hello world failed: %s", message);
     	result = 1;
    }
    
    release(message);
    release(login);
    
    return result;
}

Die Java / cscript Schnittstelle unterstützt die unten aufgelisteten Datentypen sowohl als Parameter/ als auch als Rückgabewerte.

Generell gilt in cscript:

Auch hierzu einige Beispiele:
// Richtig:
WorkflowStatus status = 0;
status = getStatusOfPublication("67110123");
publication::workflowstatus::release(status);

// Falsch:
WorkflowStatus status = publication::workflowstatus::alloc();
status = getStatusOfPublication("67110123");
publication::workflowstatus::release(status);
// Warum? Weil der ursprüngliche Speicher für status nirgendwo mehr 
// referenziert wird, also nicht mehr gelöscht werden kann.

// Richtig, aber fragwürdig:
WorkflowStatus status = publication::workflowstatus::alloc();
publication::workflowstatus::release(status);
status = getStatusOfPublication("67110123");
publication::workflowstatus::release(status);

// Richtig, aber fragwürdig:
char * publicationId = "67110123";
publicationId = findParentPublication(publicationId);
release(publicationId);

// Falsch!
int n = getMax(17, 23);
release(n);
Hinweis an Java Plugin Entwickler: alle unterstützten Comet-Datentypen (RecordID etc.) finden sich inklusive Dokumentation im CometBridgeSDK.jar, Paket com.priint.pubserver.comet.bridge.entitydata, in der folgenden Tabelle abgekürzt mit c.p.p.c.b.e.

Da für die Abbildung im Comet Daten immer transformiert werden müssen, können Klassen des EntityModels (Bucket, Text, KeyValue etc.) sowie des Publication Management Planners nicht direkt verwendet werden.
Ebenfalls im CometBridgeSDK finden sich aber Hilfsklassen und Methoden, z.B. für die Umrechung und Auswertung von IDs, Standard-Mapping etc.
Java Typ CScript Typ CScript Typ (out) Bemerkungen
void, Void int - in cscript gibt es keine void Entsprechung. Der Rückgabewert kann in diesem Falle ignoriert werden, als Parameter (in Java ist die Klasse "Void" als Parametertyp erlaubt) muss dann ein int übergeben werden.
boolean, Boolean int int* Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen
byte, Byte int int* Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen
short, Short int int* Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen
int, Integer int int*  
long, Long int int*  
BigDecimal int int* Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen
BigInteger int int* Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen
float, Float float float*  
double, Double float float*  
String char* char**

Für die cscript Ergebnisvariable darf vorher kein Speicher allokiert werden (siehe oben). Die Variable muss jedoch nach Funktionsaufruf mit release wieder freigegeben werden.

Freigabe:
  release(str);

c.p.p.c.b.e
    .RecordId
IDType IDType*

Freigabe:
  idtype
    ::release(id)
;

c.p.p.c.b.e
    .Parameter
Parameter Parameter*

Freigabe:
  publication
    ::parameter
    ::release(param)
;

c.p.p.c.b.e
    .Product
Product Product*

Freigabe:
  product
    ::release(p)
;

c.p.p.c.b.e
    .Publication
Publication Publication*

Freigabe:
  publication
    ::release(pub)
;

c.p.p.c.b.e
    .PublicationType
PublicationType PublicationType*

Freigabe:
  publication
    ::publication
    ::release(pubType)
;

c.p.p.c.b.e
    .WorkflowStatus
WorkflowStatus WorkflowStatus*

Freigabe:
  publication
    ::workflowstatus
    ::release(status)
;

c.p.p.c.b.e
    .Element
Element Element*

Freigabe:
  element
    ::release(obj)
;

c.p.p.c.b.e
    .Planning
Planning Planning*

Freigabe:
  publication
    ::planning
    ::release(planning)
;

java.util.List
    <Boolean>
List List*

Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen

Freigabe:
  list
    ::release(intList)
;

java.util.List
    <Byte>
List List*

Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen

Freigabe:
  list
    ::release(intList)
;

java.util.List
    <Short>
List List*

Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen

Freigabe:
  list
    ::release(intList)
;

java.util.List
    <Integer>
List List*

Freigabe:
  list::release(intList);

java.util.List
    <Long>
List List*

Freigabe:
  list::release(intList);

java.util.List
    <BigDecimal>
List List*

Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen

Freigabe:
  list::release(intList);

java.util.List
    <BigInteger>
List List*

Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen

Freigabe:
  list::release(intList);

java.util.List
    <Float>
FloatList FloatList*

Freigabe:
  floatlist
    ::release(floats)
;

java.util.List
    <Double>
FloatList FloatList*

Freigabe:
  floatlist
    ::release(floats)
;

java.util.List
    <String>
StringList StringList*

Freigabe:
  stringlist
    ::release(strings)
;

java.util.List
    <c.p.p.c.b.e.
        RecordId>
IDTypeList IDTypeList*

Freigabe:
  idtypelist
    ::release(ids)
;

java.util.List
    <c.p.p.c.b.e.
        Parameter>
ParameterList ParameterList*

Freigabe:
  publication
    ::parameterlist
    ::release(params)
;

java.util.List
    <c.p.p.c.b.e.
        Product>
ProductList ProductList*

Freigabe:
  productlist::release(products);

java.util.List
    <c.p.p.c.b.e.
        Publication>
PublicationList PublicationList*

Freigabe:
  publication
    ::publicationlist
    ::release(pubs)
;

java.util.List
    <c.p.p.c.b.e.
        PublicationType>
PublicationTypeList PublicationTypeList*

Freigabe:
  publication
::publicationtypelist
::release(pubTypes)
;

java.util.List
    <c.p.p.c.b.e.
        WorkflowStatus>
WorkflowStatusList WorkflowStatusList*

Freigabe:
  publication
    ::workflowstatuslist
    ::release(states)
;

java.util.List
    <c.p.p.c.b.e.
        Element>
ElementList ElementList*

Freigabe:
  elementlist
    ::release(elements)
;

java.util.List
    <c.p.p.c.b.e.
        Planning>
PlanningList PlanningList*

Freigabe:
  publication
    ::planninglist
    ::release(plannings)
;

java.util.List<c.p.p.c.b.e.KeyValue>

c.p.p.c.b.e.KeyValueList
KeyValues KeyValues*

Release:
  keyvalues::release(values);

Die @PubServerMethod, @CometCScriptFunction und @PubServerMethodParameter Annotationen erlauben umfangreiche Dokumentation der Java Methoden und zugehörigen cscript Funktionen.
Im Ison cscript-Editor wird das derzeit (4.0.5 alpha) noch nicht unterstützt, so dass cscript Entwickler diese Information aus den Java Klassen ableiten müssen oder sich mit einem geeigneten Werkzeug generierte und dokumentierte "Header" anzeigen lassen können.

Am einfachsten geht das mit dem Panel "Platzhalter-Werte" bzw. "Placeholder Values" der InDesign® Plug-Ins (Voraussetzung ist eine Comet Entwickler-Lizenz).

Im Feld "Script / File ID" kann eine File-ID angegeben werden, die bei Klick auf den Speichern-Button vom SOAP Service angefordert und lokal gespeichert wird (alternativ bei Klick auf den Bleistift: direktes Öffnen im InDesign® Script Editor).

Ausgangspunkt ist Aufruf der File-ID [pubserver]/plugins.c, diese listet alle verfügbaren "CScript"-Plugins (bzw. die zugehörigen #include-Anweisungen) auf, Beispiel:

#include "[pubserver]/plugin/com.priint.pubserver.comet.cscript.HelloWorld.c"
#include "[pubserver]/plugin/com.priint.pubserver.comet.cscript.PrimitiveTypes.c"
#include "[pubserver]/plugin/com.priint.pubserver.comet.bridge.cscript.CScriptStandardLibrary.c" 

Nun kann dieser Vorgang nacheinander für alle Includes von Interesse wiederholt werden.

Alternativ kann auch [pubserver]/plugins.h aufgerufen werden, das gibt direkt alle verfügbaren Funktions-Signaturen inklusive Inline Dokumentation (soweit aus den Annotationen ableitbar) aus. Dieser Code dient rein dokumentativen Zwecken, er kann nicht direkt in cscript eingebunden werden.

/**
 * <p>sophisticated hello world example</p>
 * <p>
 *   This is a more sophisticated hello world example.
 *   
 *   The PubServerMethod label and description are used for cscript inline
 *   documentation.
 *   Try downloading
 *     [pubserver]/plugin/com.priint.pubserver.comet.cscript.HelloWorld.h
 *   from your client application (e.g. InDesign® Desktop), to see the effect.
 *   The following cscript code calls this method:
 *   <pre>
 *     #include "[pubserver]/plugin/com.priint.pubserver.comet.cscript.HelloWorld.c"
 *     int main() {
 *       char * login = alloc(4096);
 *       char * hello = helloWorld3(system::login(login));
 *       showmessage("Server said: %s", hello);
 *       release(hello);
 *       release(login);
 *       return 0;
 *     }
 *   </pre>
 * </p>
 * @return char*
 * @param char* login user login on the client host
 */
char* helloWorld(char* login);
...
Dies funktioniert sowohl für alle Plugins (die wenigstens eine cscript Funktion bereitstellen) als auch für ein einzelnes Plugin, in diesem Fall wäre die einzutragende File ID z.B.
[pubserver]/plugin/com.priint.pubserver.comet.cscript.HelloWorld.c.

 


Frage

Kann pro Plugin immer nur eine Java / cscript Methode definiert werden?

Antwort

Nein, natürlich können beliebig viele definiert werden. Zu viele sollten sie nicht sein, aus den ganz allgemeinen Überlegungen, dass dann umso mehr Code verarbeitet werden muss, jedesmal, wenn auch nur eine Funktion des Plugins benötigt wird (dies spricht auch deutlich gegen etwaige Überlegungen, der Einfachheit halber immer gleich "[pubserver]/plugins.c" zu laden)
Aus einem zweiten Grund könnten zu viele Methoden in einem Plugin problematisch sein: es ist nicht möglich, Methoden zu überladen.
Dies ist eine Einschränkung von cscript: Funktionsnamen (und nicht lediglich -signaturen) müssen eindeutig sein.

Die daraus folgende Einschränkung für Java CSript Plugins gilt sowohl innerhalb eines Plugins sowie für alle Plugins, die gleichzeitig in einem cscript eingebunden werden sollen: wenn Plugin A eine Funktion namens foo definiert (egal mit welchen Parametern) und Plugin B ebenfalls, können diese Plugins nicht gleichzeitig in einem cscript eingebunden werden.


Frage

Kann ich bestehende Java Methoden als CScript Funkionen freigeben?

Antwort

Prinzipiell ja. Voraussetzung ist, dass Ihre Methoden zu einer als PubServerPlugin bereitgestellten Klasse gehören und dass die oben genannten Einschränkungen hinsichtlich unterstützter Datentypen erfüllt sind. In diesem Fall reicht es, wenn Sie Ihre Methode zusätzlich als @CometCScriptFunction annotieren.


Frage

Wie sieht es mit der Performance aus?

Antwort

Technisch passiert Folgendes: cscript Objekte und Werte werden nach einer festgelegten Vorschrift nach XML serialisiert, das ganze über SOAP an den PubServer geschickt, der das XML auspackt, über Methoden des PubServerSDK an das verantwortliche Plugin schickt, das Ergebnis auswertet und - wiederum in XML und eine SOAP Nachricht verpackt - zurück an die Plugins schickt, wo die Nachricht wieder ausgepackt, ausgewertet und das Ergebnis den entsprechenden cscript-Variablen zugewiesen wird. Das klingt nach Aufwand und kostet natürlich Zeit.

Typische Zeiten für einen Roundtrip ohne wesentliche Berechnungen auf Server-Seite sind 30ms (wesentlich mehr sollte es nicht sein, andernfalls lohnt es sich schon unter generellen Perfromance-Gesichtspunkten nach möglichen Engstellen in der Netzwerk / Serverumgebung zu forschen).
30ms sind vertretbarer Overhead, wenn auf Server-Seite einigermaßen komplexe Berechnungen angestellt werden (etwa die Ermittlung aller verplanten Artikel für ein Dokument) oder wenn es sich um eher seltene Aufrufe handelt (einmalige Aktionen bei Login, beim Öffnen eines Dokuments, Platzieren eines Produkts etc.).
Es ist deutlich zu lange für String-Operationen (strcmp, strcpy, strcat ...) oder einfache Berechnungen, die ebensogut und sehr viel performanter direkt in cscript gelöst werden können.


Frage

Warum wird der char bzw. Character Datentyp nicht unterstützt?

Antwort

Es gibt in den XML Schema builtin Datentypen keinen sinnvoll direkt verwendbaren Typ für einzelne Zeichen, Vorschriften für die Serialisierung / Deserialisierung hätten relativ aufwändig extra implementiert werden müssen.
Gravierender aber: Strings werden in cscript in UTF-8 kodiert, ein einzelnes Zeichen kann also aus mehreren char's bestehen. In allen cscript-Stringoperationen wird dies berücksichtigt, alle Indizes und Längen-Anaben beziehen sich auf die dargestellten Zeichen.
Der Zugriff auf einen einzelnen char (oder byte) ist also durchaus fehleranfällig. Angesichts der sehr wenigen Funktionen in cscript, die überhaupt einzelne Zeichen als Parameter oder Rückgabewert erfordern, scheint die Unterstützung in der csript / Java Schnittstelle verzichtbar.


Frage

Wie groß können Ergebnis-Strings einer Java Methode maximal sein?

Antwort

Theoretisch beliebig. Der erforderliche Speicher wird in cscript dynamisch allokiert.


Frage

Ist die Anzahl / Größe der Parameter beschränkt?

Antwort

Nein - zumindest nicht, was die Übersetzung und Übertragung betrifft. Ob es in cscript oder Java eine Begrenzung gibt, weiß ich um ehrlich zu sein nicht. Sofern ja, jabe ich die vermutlich bislang nicht annähernd ausgeschöpft.


Frage

Werden Tags (wie etwa <Record.Id> ...) in Skripten, die Java-Methoden aufrufen, unterstützt?

Antwort

Java Methoden können in prinzipiell jedem cscript eingebunden werden, Platzhalter-Skripte, Panel-Skripte, Gestaltungsregeln, Aufbau-Skripte etc.
Welche Tags und Umgebungsvariablen verfügbar sind, hängt von der jeweiligen Aufruf-Umgebung ab, ansonsten gibt es hier keine Besonderheiten.


Frage

Kann in den Java Methoden auf Dokument-Eigenschaften zugegriffen werden?

Antwort

Nur auf diejenigen, die als Parameter übergeben werden. Es gibt keinen "Rückweg", also keine Möglichkeit, in einer Java Methode eben mal InDesign® zurückzurufen, um die Position eines Rahmens zu ermitteln (oder ihn etwa gleich zu verschieben).


Frage

Es war jetzt einige Male von "InDesign®" die Rede - wird der Aufruf von Java Methoden in cscript denn auch im PDF Renderer unterstützt?

Antwort

natürlich