Description: Used for implementing code extensions that can be invoked as an N4 REST web service. When the expected parameters are passed to the code extension, it returns a string value. N4 extracts input parameters from the URL query parameters. The string output is returned in the HTTP response body. N4 requires a user name, password, N4 scope values, and a code extension name to be sent as part of the invocation of the REST web service. See REST API User Documentation under Code Extension User Guidelines in the the N4 3.0 SDK manualfor details about creating and configuring the N4 REST web service.
Abstract Base Class: AbstractSimpleRequest
Method: AbstractJSONDomainQueryExecutor.getConverter()
Interface: ESimpleReadRequest
Module: Framework
Version Added: 2.6
Requires Code Extension Name or Name Pattern: No
Code Extension Name or Name Pattern: N/A
Where to Specify Code Extensions of this Type: To configure a code extension of this type, you must:
Create and enable a custom code extension that passes:
Scope coordinates as follows: http://yourserver/apex/api/codeextension?extensionname=ExampleHelloWorldService&operatorId=OPR&complexId=CPLX&facilityId=FAC&yardId=YARD
Parameters prefixed by PARM_. For example, if you have a parameter named RELATIVE_TIME, the REST parameter should be sent as PARM_RELATIVE_TIME
Create a dedicated user that has a role with the following privilege enabled: ‘Execute Code Extensions via REST Protocol (on page 1)’
For authorization, add the dedicated user with the "Universal Query API Access - Allow" privilege.
For authentication, uses HTTP Basic Authentication. This means that the HTTP Header name must be 'Authorization', and the value 'user:pass', where 'user' is the user name and 'pass' is the password, must be Base64 encoded.
Enable the N4 setting FRMCARINA032 (CODE_EXTENSION_BY_REST_ENABLE) (on page 1) at a scope level that is appropriate to the task.
For example, if you are creating a scoped copy of the system-seeded UpdateCheLastKnownYardPosition code extension, which uses this type, you would enable that setting at the Yard scope. Or, if you create a custom code extension to obtain all berthings across the facility, you could scope it at the Complex, Operation, or Global scope, depending on your preference.
System-Seeded Code Extensions Using this Type: UpdateCheLastKnownYardPosition
Code Example
The following sample code implements a custom REST web service for creating a berth scheduler.
To view the JSON formatted, use http://www.jsoneditoronline.org.
The URL will be something like this:
http://localhost:8280/apex/api/codeextension?extensionname=BerthSchedulerJSONDataExtract&PARM_RELATIVE_TIME=CURRENT_MONTH&operatorId=TRNG
The sample code:
<?xml version="1.0" encoding="UTF-8"?>
<cnx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schemas/cnx.xsd">
<entity id="com.navis.extension.business.Extension">
<field id="extName">BerthModelJSONDataExtract</field>
<field id="extLang">GROOVY</field>
<field id="extType">REQUEST_SIMPLE_READ</field>
<field id="extVersion">3</field>
<field id="extEnabled">true</field>
<field id="extScopeLevel">1</field>
<field id="extCreator">admin</field>
<field id="extChanged">2013-01-04T10:55:38 -0800</field>
<field id="extSysSeeded">false</field>
<field id="extContents"><![CDATA[/*
* Copyright (c) 2013 Navis LLC. All Rights Reserved.
*
*/
package extension.groovy
import com.navis.external.framework.web.service.AbstractJSONDomainQueryExecutor
import com.navis.framework.metafields.MetafieldId
import com.navis.framework.metafields.MetafieldIdFactory
import com.navis.framework.portal.QueryUtils
import com.navis.framework.portal.UserContext
import com.navis.framework.portal.query.DomainQuery
import com.navis.framework.portal.query.PredicateFactory
import com.navis.yard.YardEntity
import com.navis.yard.YardField
import org.apache.commons.lang.StringUtils
/**
* use PARM_BERTH_NAME to narrow down to berth. returns all if requested or is narrowed by login scopes
*/
public class BerthModelJSONDataExtract extends AbstractJSONDomainQueryExecutor {
@Override
protected DomainQuery getQuery(UserContext inContext, Map inParameters) {
// this gets everything. Pass in the BERTH Model NAME
DomainQuery q = QueryUtils.createDomainQuery(YardEntity.BERTH_USER_RANGE);
q.addDqField(YardField.UBR1_D_SEQUENCE);
q.addDqField(YardField.UBR_CODE);
q.addDqField(YardField.UBR_NAME);
q.addDqField(YardField.UBR1_D_START_LOC_CM);
q.addDqField(YardField.UBR1_D_END_LOC_CM);
q.addDqField(YardField.UBR_BERTH_RANGE_TYPE);
q.setScopingEnabled(false);
String name = inParameters.get("BERTH_NAME");
MetafieldId BERTH_NAME = MetafieldIdFactory.getCompoundMetafieldId(YardField.UBR_OWNING_BERTH_MODEL, YardField.BRM_NAME);
if (StringUtils.isNotEmpty(name)) {
q.addDqPredicate(PredicateFactory.eq(BERTH_NAME, name))
}
return q;
}
}]]></field>
<field id="extCreated">2013-01-04T10:54:37 -0800</field>
<field id="extChanger">admin</field>
</entity>
<entity id="com.navis.extension.business.Extension">
<field id="extName">BerthSchedulerJSONDataExtract</field>
<field id="extLang">GROOVY</field>
<field id="extType">REQUEST_SIMPLE_READ</field>
<field id="extVersion">10</field>
<field id="extEnabled">true</field>
<field id="extScopeLevel">1</field>
<field id="extCreator">admin</field>
<field id="extChanged">2013-01-08T14:16:13 -0800</field>
<field id="extSysSeeded">false</field>
<field id="extContents"><![CDATA[/*
* Copyright (c) 2013 Navis LLC. All Rights Reserved.
*
*/
package extension.groovy
import com.navis.argo.ArgoField
import com.navis.argo.ArgoRefField
import com.navis.external.framework.request.ESimpleResponseConverter
import com.navis.external.framework.web.service.AbstractJSONDomainQueryExecutor
import com.navis.external.framework.web.service.DefaultJSONResponseConverter
import com.navis.framework.business.atoms.PredicateVerbEnum
import com.navis.framework.business.atoms.RelativeTimeEnum
import com.navis.framework.metafields.MetafieldId
import com.navis.framework.metafields.MetafieldIdFactory
import com.navis.framework.portal.Ordering
import com.navis.framework.portal.QueryUtils
import com.navis.framework.portal.UserContext
import com.navis.framework.portal.context.UserContextUtils
import com.navis.framework.portal.query.DomainQuery
import com.navis.framework.portal.query.PredicateFactory
import com.navis.framework.util.internationalization.ITranslationContext
import com.navis.vessel.VesselEntity
import com.navis.vessel.VesselField
import com.navis.vessel.api.VesselVisitField
import com.navis.vessel.business.atoms.BerthSideTypeEnum
import org.apache.commons.lang.StringUtils
/**
* http://localhost:8280/apex/api/codeextension?extensionname=BerthSchedulerDataExtract
* <p/>
* or with parameters
*
* http://localhost:8280/apex/api/codeextension?extensionname=BerthSchedulerJSONDataExtract&PARM_RELATIVE_TIME=LAST_SEVEN_DAYS&operatorId=TRNG
*/
public class BerthSchedulerJSONDataExtract extends AbstractJSONDomainQueryExecutor {
@Override
protected DomainQuery getQuery(UserContext inContext, Map inParameters) {
MetafieldId BERTH_VVD_ID =
MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_VVD, VesselVisitField.VVD_ID);
MetafieldId INBOUND_VOYAGE = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_VVD, VesselVisitField.VVD_IB_VYG_NBR);
MetafieldId OUTBOUND_VOYAGE = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_VVD, VesselVisitField.VVD_OB_VYG_NBR);
MetafieldId BERTH_VESSEL = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_VVD, VesselField.VVD_VESSEL);
MetafieldId BERTH_VESSEL_CLASS = MetafieldIdFactory.getCompoundMetafieldId(BERTH_VESSEL, VesselField.VES_VESSEL_CLASS);
MetafieldId BERTH_VESSEL_NAME = MetafieldIdFactory.getCompoundMetafieldId(BERTH_VESSEL, VesselField.VES_NAME);
MetafieldId BERTH_VESSEL_CLASS_ID = MetafieldIdFactory.getCompoundMetafieldId(BERTH_VESSEL_CLASS, VesselField.VESCLASS_ID);
MetafieldId BERTH_SHIP_LOA = MetafieldIdFactory.getCompoundMetafieldId(BERTH_VESSEL_CLASS, VesselField.VESCLASS_LOA_CM);
MetafieldId BERTH_SHIP_WIDTH = MetafieldIdFactory.getCompoundMetafieldId(BERTH_VESSEL_CLASS, VesselField.VESCLASS_BEAM_CM);
MetafieldId BERTH_QUAY_ID = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_QUAY, ArgoField.QUAY_ID);
MetafieldId BERTH_QUAY_NAME = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_QUAY, ArgoField.QUAY_NAME);
MetafieldId BIZ_UNIT = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_VVD, VesselVisitField.VVD_BIZU);
MetafieldId LINE_OPERATOR = MetafieldIdFactory.getCompoundMetafieldId(BIZ_UNIT, ArgoRefField.BZU_ID);
MetafieldId SERVICE = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_VVD, VesselVisitField.VVD_SERVICE);
MetafieldId SERVICE_NAME = MetafieldIdFactory.getCompoundMetafieldId(SERVICE, ArgoRefField.SRVC_NAME);
MetafieldId EST_LOAD = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_VVD, VesselVisitField.VVD_ESTMC_LOAD);
MetafieldId EST_DISCHARGE = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_VVD, VesselVisitField.VVD_ESTMC_DISCHARGE);
MetafieldId EST_RESTOW = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_VVD, VesselVisitField.VVD_ESTMC_RESTOW);
MetafieldId EST_SHIFT = MetafieldIdFactory.getCompoundMetafieldId(VesselField.BRTHG_VVD, VesselVisitField.VVD_ESTMC_SHIFT);
DomainQuery q = QueryUtils.createDomainQuery(VesselEntity.VESSEL_VISIT_BERTHING);
q.addDqField(BERTH_VVD_ID);
q.addDqField(BERTH_VESSEL_NAME);
q.addDqField(VesselField.BRTHG_SHIP_SIDE_TO);
q.addDqField(BERTH_QUAY_ID);
q.addDqField(BERTH_QUAY_NAME);
q.addDqField(VesselField.BRTHG_E_T_A);
q.addDqField(VesselField.BRTHG_E_T_D);
q.addDqField(BERTH_VESSEL_CLASS_ID); // for debugging to change data
q.addDqField(BERTH_SHIP_LOA);
q.addDqField(BERTH_SHIP_WIDTH);
q.addDqOrdering(Ordering.asc(VesselField.BRTHG_E_T_A));
q.addDqOrdering(Ordering.asc(BERTH_QUAY_NAME));
q.addDqField(LINE_OPERATOR);
q.addDqField(SERVICE_NAME);
q.addDqField(INBOUND_VOYAGE);
q.addDqField(OUTBOUND_VOYAGE);
q.addDqField(EST_LOAD);
q.addDqField(EST_DISCHARGE);
q.addDqField(EST_RESTOW);
q.addDqField(EST_SHIFT);
// Predicate for relative time which is optional
String time = inParameters.get("RELATIVE_TIME");
if (StringUtils.isNotBlank(time)) {
RelativeTimeEnum timeEnum = RelativeTimeEnum.getEnum(time);
q.addDqPredicate(PredicateFactory.createPredicate(inContext, VesselField.BRTHG_E_T_A, PredicateVerbEnum.TIME_IS, timeEnum));
}
return q;
}
//script runner to generate the variform
public String generateVariformColumns() {
DomainQuery q = getQuery(UserContextUtils.getSystemUserContext(), new HashMap());
StringBuilder buf = new StringBuilder();
for (String field : q.getFields()) {
buf.append("<column fieldId=\"" + field + "\"/>\n");
}
return buf.toString();
}
protected ESimpleResponseConverter getConverter() {
if (_converter == null) {
_converter = new BerthFieldConverter();
}
return _converter;
}
private static class BerthFieldConverter extends DefaultJSONResponseConverter {
@Override
public Object translateValue(ITranslationContext inContext, MetafieldId inFieldId, Object inFieldValue) {
if (inFieldValue instanceof BerthSideTypeEnum) {
return ((BerthSideTypeEnum) inFieldValue).getName();
} else if (inFieldValue instanceof Date) {
// return java millis
return ((Date) inFieldValue).getTime();
}
return super.translateValue(inContext, inFieldId, inFieldValue);
}
}
private BerthFieldConverter _converter;
}]]></field>
<field id="extCreated">2013-01-04T11:02:20 -0800</field>
<field id="extChanger">admin</field>
</entity>
<entity id="com.navis.framework.navigation.business.CustomNode">
<field id="custnodeVariformId">CUSTOM_BERTHINGS</field>
<field id="custnodeMenuContext">/ulc/ApexNavigationTree.xml</field>
<field id="custnodeScopeLevel">1</field>
<field id="custnodeId">CUSTOM_NODE_BERTHINGS</field>
<field id="custnodeChanged">2013-01-08T13:59:34 -0800</field>
<field id="custnodeCreator">admin</field>
<field id="custnodeParentId">MID_VESSEL</field>
<field id="custnodePosition">AFTER_NODE</field>
<field id="custnodeLabel">Berthing</field>
<field id="custnodeCreated">2013-01-08T13:58:50 -0800</field>
<field id="custnodeChanger">admin</field>
<field id="custnodePrecedingId">VesselSchedule</field>
<field id="custnodeEnabled">true</field>
</entity>
<entity id="com.navis.framework.configuration.variform.DbVariformFileDefinition">
<field id="cfgvarVariformIds"><![CDATA[|CUSTOM_BERTHINGS|]]></field>
<field id="cfgvarScopeLevel">1</field>
<field id="cfgvarCreator">admin</field>
<field id="cfgvarChanger">admin</field>
<field id="cfgvarName">Berthings</field>
<field id="cfgvarVariformXml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<variforms xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schemas/Variforms.xsd">
<actions>
<!--
These are the most common used actions. Please verify needs and edit accordingly.
-->
<action id="view">view</action>
<action id="create">create</action>
<action id="update">update</action>
<action id="delete">delete</action>
<action id="query">query</action>
</actions>
<table id="CUSTOM_BERTHINGS">
unit
<name>VesselVisitBerthing</name>
</entity>
<tableActions>
<tableActionMode action="create" mode="allow" />
<tableActionMode action="update" mode="allow" />
<tableActionMode action="view" mode="allow" />
<tableActionMode action="delete" mode="allow" />
</tableActions>
<column fieldId="brthgVvd.cvdCv.cvId"/>
<column fieldId="brthgVvd.vvdVessel.vesName"/>
<column fieldId="brthgShipSideTo"/>
<column fieldId="brthgQuay.quayId"/>
<column fieldId="brthgQuay.quayName"/>
<column fieldId="brthgETA"/>
<column fieldId="brthgETD"/>
<column fieldId="brthgVvd.vvdVessel.vesVesselClass.vesclassId"/>
<column fieldId="brthgVvd.vvdVessel.vesVesselClass.vesclassLoaCm"/>
<column fieldId="brthgVvd.vvdVessel.vesVesselClass.vesclassBeamCm"/>
<column fieldId="brthgVvd.vvdBizu.bzuId"/>
<column fieldId="brthgVvd.cvdService.srvcName"/>
<column fieldId="brthgVvd.vvdIbVygNbr"/>
<column fieldId="brthgVvd.vvdObVygNbr"/>
<column fieldId="brthgVvd.vvdEstMoveCount.mcLoad"/>
<column fieldId="brthgVvd.vvdEstMoveCount.mcDischarge"/>
<column fieldId="brthgVvd.vvdEstMoveCount.mcRestow"/>
<column fieldId="brthgVvd.vvdEstMoveCount.mcShift"/>
</table>
</variforms>]]></field>
<field id="cfgvarChanged">2013-01-08T13:59:06 -0800</field>
<field id="cfgvarEnabled">true</field>
<field id="cfgvarCreated">2013-01-08T13:54:54 -0800</field>
</entity>
</cnx>