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
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> | gPSRootTableRecordId | Id des Datensatzes der Tabelle |
<RootTableRecord.GroupId> | gPSRootTableGroupId | Group Id des Datensatzes der Tabelle |
<RootTableEntity.Id> | gPSRootTableEntityId | Identifier der Entität der Tabelle |
<RootTableEntity.Class> | gPSRootTableEntityClass | Klasse der Entität der Tabelle |
<RootTableRecord.ParentId> | gPSRootTableParentRecordId | Id des Parent-Datensatzes der Tabelle |
<RootTableRecord.ParentGroupId> | gPSRootTableParentGroupId | Group Id des Parent Datensatzes der Tabelle |
<RootTableEntity.ParentId> | gPSRootTableParentEntityId | Identifier der Entität des Parents der Tabelle |
<RootTableEntity.ParentClass> | gPSRootTableParentEntityClass | Klasse der Entität des Parents der Tabelle |
<ColumnRecord.Id> | gPSColumnRecordId | Id des Datensatzes der Spalte |
<ColumnRecord.GroupId> | gPSColumnGroupId | Group Id des Datensatzes der Spalte |
<ColumnEntity.Id> | gPSColumnEntityId | Identifier der Entität der Spalte |
<ColumnEntity.Class> | gPSColumnEntityClass | Klasse der Entität der Spalte |
<ColumnRecord.ParentId> | gPSColumnParentRecordId | Id des Parent-Datensatzes der Spalte |
<ColumnRecord.ParentGroupId> | gPSColumnParentGroupId | Group Id des Parent Datensatzes der Spalte |
<ColumnEntity.ParentId> | gPSColumnParentEntityId | Identifier der Entität des Parents der Spalte |
<ColumnEntity.ParentClass> | gPSColumnParentEntityClass | Klasse der Entität des Parents der Spalte |
<RowRecord.Id> | gPSRowRecordId | Id des Datensatzes der Zeile |
<RowRecord.GroupId> | gPSRowGroupId | Group Id des Datensatzes der Zeile |
<RowEntity.Id> | gPSRowEntityId | Identifier der Entität der Zeile |
<RowEntity.Class> | gPSRowEntityClass | Klasse der Entität der Zeile |
<RowRecord.ParentId> | gPSRowParentRecordId | Id des Parent-Datensatzes der Zeile |
<RowRecord.ParentGroupId> | gPSRowParentGroupId | Group Id des Parent Datensatzes der Zeile |
<RowEntity.ParentId> | gPSRowParentEntityId | Identifier der Entität des Parents der Zeile |
<RowEntity.ParentClass> | gPSRowParentEntityClass | Klasse der Entität des Parents der Zeile |
<CellRecord.Id> | gPSCellRecordId | Id des Datensatzes der Zelle |
<CellRecord.GroupId> | gPSCellGroupId | Group Id des Datensatzes der Zelle |
<CellEntity.Id> | gPSCellEntityId | Identifier der Entität der Zelle |
<CellEntity.Class> | gPSCellEntityClass | Klasse der Entität der Zelle |
<CellRecord.ParentId> | gPSCellParentRecordId | Id des Parent-Datensatzes der Zelle |
<CellRecord.ParentGroupId> | gPSCellParentGroupId | Group Id des Parent Datensatzes der Zelle |
<CellEntity.ParentId> | gPSCellParentEntityId | Identifier der Entität des Parents der Zelle |
<CellEntity.ParentClass> | gPSCellParentEntityClass | Klasse 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"Mehr hierzu siehe in Abschnitt Aufruf eigener Java Plugins.
// Shortcut for: #include "[pubserver]/plugin/com.priint.pubserver.comet.bridge.cscript.CScriptStandardLibrary.h"
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
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:
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.
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
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:
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; }
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:
@PubServerMethod(type=PluginMethod.MethodType.GENERIC) @CometCScriptFunction(name="alloc_") public int alloc(...
@PubServerMethod(type=PluginMethod.MethodType.GENERIC) @CometCScriptFunction public int min( @PubServerMethodParameter(name="value1") int n1, @PubServerMethodParameter(name="value2") int n2) ...wobei es eigentlich fast keiner Erwähnung bedarf, dass Folgendes zu Fehlern führt:
@PubServerMethod(type=PluginMethod.MethodType.GENERIC) @CometCScriptFunction public int min( @PubServerMethodParameter(name="value") int n1, @PubServerMethodParameter(name="value") int n2) ...Parameternamen sollten nicht mit __gcs beginnen, da wir dieses Prefix für lokale Variablen etc. benutzen. Das folgende Beispiel wird ebenfalls nicht funktionieren, auch wenn der Fehler nicht sofort offensichtlich ist:
@PubServerMethod(type=PluginMethod.MethodType.GENERIC) @CometCScriptFunction public int min( @PubServerMethodParameter int n1, @PubServerMethodParameter(name="__gcsarg1_") int n2) ...
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:
@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);
@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");
@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); }
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:
// 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.
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: |
c.p.p.c.b.e .RecordId |
IDType | IDType* | Freigabe: |
c.p.p.c.b.e .Parameter |
Parameter | Parameter* | Freigabe: |
c.p.p.c.b.e .Product |
Product | Product* | Freigabe: |
c.p.p.c.b.e .Publication |
Publication | Publication* | Freigabe: |
c.p.p.c.b.e .PublicationType |
PublicationType | PublicationType* | Freigabe: |
c.p.p.c.b.e .WorkflowStatus |
WorkflowStatus | WorkflowStatus* | Freigabe: |
c.p.p.c.b.e .Element |
Element | Element* | Freigabe: |
c.p.p.c.b.e .Planning |
Planning | Planning* | Freigabe: |
java.util.List <Boolean> |
List | List* | Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen Freigabe: |
java.util.List <Byte> |
List | List* | Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen Freigabe: |
java.util.List <Short> |
List | List* | Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen Freigabe: |
java.util.List <Integer> |
List | List* | Freigabe: |
java.util.List <Long> |
List | List* | Freigabe: |
java.util.List <BigDecimal> |
List | List* | Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen Freigabe: |
java.util.List <BigInteger> |
List | List* | Beachten Sie mögliche Datenverluste aufgrund der unterschiedlichen Speichergrößen Freigabe: |
java.util.List <Float> |
FloatList | FloatList* | Freigabe: |
java.util.List <Double> |
FloatList | FloatList* | Freigabe: |
java.util.List <String> |
StringList | StringList* | Freigabe: |
java.util.List <c.p.p.c.b.e. RecordId> |
IDTypeList | IDTypeList* | Freigabe: |
java.util.List <c.p.p.c.b.e. Parameter> |
ParameterList | ParameterList* | Freigabe: |
java.util.List <c.p.p.c.b.e. Product> |
ProductList | ProductList* | Freigabe: |
java.util.List <c.p.p.c.b.e. Publication> |
PublicationList | PublicationList* | Freigabe: |
java.util.List <c.p.p.c.b.e. PublicationType> |
PublicationTypeList | PublicationTypeList* |
Freigabe: |
java.util.List <c.p.p.c.b.e. WorkflowStatus> |
WorkflowStatusList | WorkflowStatusList* | Freigabe: |
java.util.List <c.p.p.c.b.e. Element> |
ElementList | ElementList* | Freigabe: |
java.util.List <c.p.p.c.b.e. Planning> |
PlanningList | PlanningList* | Freigabe: |
java.util.List<c.p.p.c.b.e.KeyValue> c.p.p.c.b.e.KeyValueList |
KeyValues | KeyValues* | Release: |
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.
Kann pro Plugin immer nur eine Java / cscript Methode definiert werden?
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.
Kann ich bestehende Java Methoden als CScript Funkionen freigeben?
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.
Wie sieht es mit der Performance aus?
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.
Warum wird der char bzw. Character Datentyp nicht unterstützt?
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.
Wie groß können Ergebnis-Strings einer Java Methode maximal sein?
Theoretisch beliebig. Der erforderliche Speicher wird in cscript dynamisch allokiert.
Ist die Anzahl / Größe der Parameter beschränkt?
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.
Werden Tags (wie etwa <Record.Id> ...) in Skripten, die Java-Methoden aufrufen, unterstützt?
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.
Kann in den Java Methoden auf Dokument-Eigenschaften zugegriffen werden?
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).
Es war jetzt einige Male von "InDesign®" die Rede - wird der Aufruf von Java Methoden in cscript denn auch im PDF Renderer unterstützt?
natürlich