2017 June Release

Implementing triggersPermanent link for this heading

There are two types of triggers in Fabasoft Folio:

  • object-level triggers fired for specific events involving objects
  • property-level triggers fired for specific events involving properties

Triggers are executed in the background and therefore cannot involve user interaction. Furthermore, please note that triggers must not be implemented as virtual applications.

Note: Triggers should be defined as actions. Omit the usecase keyword when defining new triggers using the app.ducx use case language.

Object-level triggersPermanent link for this heading

Object-level triggers are defined in object class COOSYSTEM@1.1:Object and are invoked automatically by Fabasoft Folio.

You can override object-level triggers for your object classes to change or add to their default behavior.

When overriding an object-level trigger, the fully qualified reference of the trigger action must be denoted, followed by curly braces.

The implementation of an overridden object-level trigger should usually call the super method. In app.ducx expression language, this can be accomplished by the following statement:

cooobj.CallMethod(cootx, coometh);

Constructor triggerPermanent link for this heading

The object constructor trigger COOSYSTEM@1.1:ObjectConstructor is fired when a new instance of an object class is created. The trigger is invoked on the new instance.

Example

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  override ObjectConstructor {
    variant Order {
      expression {
        // Call super method
        cooobj.CallMethod(cootx, coometh);
        // Add order to the list of orders stored in the current user's
        // desk object (expecting that
APPDUCXSAMPLE@200.200:userorders has
        // been added as a property of the desk object class)

        root = cooroot;
        if (root.HasAttribute(cootx, #userorders)) {
          cooobj.COODESK@1.1:ShareObject(null, null, #userorders, root);
        }
      }
    }
  }
}


The next example illustrates a Java method implementation of the same functionality as shown in the previous example.

Example

app.ducx Use Case Language

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  override ObjectConstructor {
    variant Order {
      java = APPDUCXSAMPLE.Order.OrderConstructor;
    }
  }
}

Java Implementation

@DUCXImplementation("COOSYSTEM@1.1:ObjectConstructor")
public void OrderConstructor(final Object sourceobj) throws CooException {
  // Call super method
  super.COOSYSTEM_1_1_ObjectConstructor(sourceobj);

  // Add order to the list of orders stored in the current user's
  // desk object (expecting that
APPDUCXSAMPLE@200.200:userorders has
  // been added as a property of the desk object class)

  RootObject root = RootObject.from(coort.GetCurrentUserRoot());
  if (root.HasAttribute(cootx, APPDUCXSAMPLE_200_300.getProperty_userorders)) {
    this.COODESK_1_1_ShareObject(null, null, APPDUCXSAMPLE_200_300.
      getProperty_userorders, root);
  }
}

Prepare commit triggerPermanent link for this heading

The prepare commit trigger COOSYSTEM@1.1:ObjectPrepareCommit is fired before any set triggers are invoked. The trigger is invoked on the object that is to be changed.

Example

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  override ObjectPrepareCommit {
    variant Order {
      expression {
        // Generate the order's name based on the name build configuration
        cooobj.FSCCONFIG@1.1001:ObjectPrepareCommitNameBuild();
      }
    }
  }
}


The next example illustrates a Java method implementation of the same functionality as shown in the previous example.

Example

app.ducx Use Case Language

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  override ObjectPrepareCommit {
    variant Order {
      java = APPDUCXSAMPLE.Order.OrderPrepareCommit;
    }
  }
}

Java Implementation

@DUCXImplementation("COOSYSTEM@1.1:ObjectPrepareCommit")
public void OrderPrepareCommit(final Boolean internalchange)
  throws CooException {
  // Generate the order's name based on the name build configuration
  this.FSCCONFIG_1_1001_ObjectPrepareCommitNameBuild();
}

Finalize commit triggerPermanent link for this heading

The finalize commit trigger COOSYSTEM@1.1:ObjectFinalizeCommit is fired after the set triggers have been invoked, but before any changes are committed to an object. The trigger is invoked on the object that is to be changed.

Example

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  override ObjectFinalizeCommit {
    variant Order {
      expression {
        // Call super method
        cooobj.CallMethod(cootx, coometh);
        // Enforce that users also have to change the list of order
        // positions when changing the vendor

        if (cootx.IsAttributeChanged(cooobj, #ordervendor)
            && !cootx.IsAttributeChanged(cooobj, #orderpositions) {
          throw coort.SetError(#InvalidChange, null);
        }
      }
    }
  }
}


The next example illustrates a Java method implementation of the same functionality as shown in the previous example.

Example

app.ducx Use Case Language

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  override ObjectFinalizeCommit {
    variant Order {
      java = APPDUCXSAMPLE.Order.OrderFinalizeCommit;
    }
  }
}

Java Implementation

@DUCXImplementation("COOSYSTEM@1.1:ObjectFinalizeCommit")
public void OrderFinalizeCommit(final List<Object> attrlist)
  throws CooException {
  // Call super method
  super.COOSYSTEM_1_1_ObjectFinalizeCommit(attrlist);

  // Enforce that users also have to change the list of order
  // positions when changing the vendor

  if (cootx.IsAttributeChanged(this, APPDUCXSAMPLE_200_300.
    getProperty_ordervendor()) && !cootx.IsAttributeChanged(this,
   APPDUCXSAMPLE_200_300.getProperty_orderpositions)) {
    coort.SetError(APPDUCXSAMPLE_200_300.getErrorMesssage_InvalidChange());
  }
}

Property-level triggersPermanent link for this heading

Property-level triggers are fired only when they are explicitly attached to a property for a predefined trigger event.

For defining a property-level trigger, you have to follow these steps:

  • Create and implement a use case for the trigger
  • Attach the trigger action to the trigger event in the property definition

For further information on how to attach a trigger action to a trigger event in a property definition, please refer to chapter “Assigning triggers to a property”.

Constructor triggerPermanent link for this heading

When a new instance of an object class is created, the constructor triggers of all properties are fired – provided that a constructor trigger has been defined for the particular property.

For a constructor trigger action, you have to assign the COOSYSTEM@1.1:AttrConstructorPrototype. The initialization value that is to be assigned to the property must be returned in the second parameter.

Example

app.ducx Object Model Language

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Order : CompoundObject {
    OrderState orderstate readonly(ui) {
      ctor = OrderStateCtor;
    }
  }
}

app.ducx Use Case Language

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  OrderStateCtor(parameters as AttrConstructorPrototype) {
    variant Order {
      expression {
        // Initialize order state as pending
        value = "OS_PENDING";
      }
    }
  }
}


The next example illustrates a Java method implementation of the same functionality as shown in the previous example.

Example

app.ducx Object Model Language

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Order : CompoundObject {
    OrderState orderstate readonly(ui) {
      ctor = OrderStateCtor;
    }
  }
}

app.ducx Use Case Language

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  OrderStateCtor(parameters as AttrConstructorPrototype) {
    variant Order {
      impl = java:APPDUCXSAMPLE.Order.OrderStateCtor;
    }
  }
}

Java Implementation

@DUCXImplementation("APPDUCXSAMPLE@200.200:OrderStateCtor")
public OrderStateCtorResult OrderStateCtor(final Object attrdef)
  throws CooException {
  // Initialize order state as pending
  OrderStateCtorResult result = new OrderStateCtorResult();
  result.value = new ArrayList<java.lang.Object>();
  result.value.add(OrderState.OS_PENDING);
  return result;
}

Get value triggerPermanent link for this heading

The get value trigger is fired, after the property value is read from the database.

For a get value trigger action, you have to assign the COOSYSTEM@1.1:AttrGetPrototype. The value read from the database is passed to the trigger in the second parameter. The implementation can then modify the value, and return the modified value – also in the second parameter.

Instead of defining a constraint, the example shown can also be implemented using a get value trigger as illustrated in the following example.

Example

app.ducx Object Model Language

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Order : CompoundObject {
    currency ordertotal readonly volatile {
      get = GetOrderTotal;
    }
  }
}

app.ducx Use Case Language

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  GetOrderTotal(parameters as AttrGetPrototype) {
    variant Order {
      expression {
        for (OrderPosition position : cooobj.orderpositions) {
          Product product = position.product;
          if (product != null) {
            currency total += product.unitprice * position.quantity;
          }
        }
        total;
      }
    }
  }
}


The next example illustrates a Java method implementation of the same functionality as shown in the previous example.

Example

app.ducx Object Model Language

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Order : CompoundObject {
    currency ordertotal readonly volatile {
      get = GetOrderTotal;
    }
  }
}

app.ducx Use Case Language

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  GetOrderTotal(parameters as AttrGetPrototype) {
    variant Order {
      java = APPDUCXSAMPLE.Order.GetOrderTotal;
    }
  }
}

Java Implementation

@DUCXImplementation("APPDUCXSAMPLE@200.200:GetOrderTotal")
public GetOrderTotalResult GetOrderTotal(final Object attrdef,
  final List<java.lang.Object> value) throws CooException {
  GetOrderTotalResult result = new GetOrderTotalResult();
  Currency ordertotal = Currency.create();
  long amount = 0;

  List<OrderPosition> positions = this.APPDUCXSAMPLE_200_300_orderpositions;

  for (OrderPosition position : positions) {
    Long quantity = position.APPDUCXSAMPLE_200_300_quantity;
    Product product = position.APPDUCXSAMPLE_200_300_product;
    Currency unitprice = product.APPDUCXSAMPLE_200_300_unitprice;
    long price = Long.parseLong(unitprice.COOSYSTEM_1_1_currvalue);
    amount += quantity * price;
  }

  ordertotal.COOSYSTEM_1_1_currsymbol = CurrencySymbol.USD;
  ordertotal.COOSYSTEM_1_1_currvalue = Long.toString(amount);

  result.value = new ArrayList<java.lang.Object>();
  result.value.add(ordertotal);
  return result;
}

Set value triggerPermanent link for this heading

The set value trigger is fired, before the property value is written to the database.

For a set value trigger action, you have to assign the COOSYSTEM@1.1:AttrSetPrototype. The current value of the property is passed to the trigger in the second parameter. The value contained in the property before it was changed is made available in the third parameter. If the value to be written to the database is changed by the implementation of the trigger, it must be returned in the second parameter.

Example

app.ducx Object Model Language

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class<ContentObjectClass> : ContentObject {
    date invoicepaymentdate {
      set = SetInvoiceDate;
    }
  }
}

app.ducx Use Case Language

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  SetInvoiceDate(parameters as AttrSetPrototype) {
    variant Invoice {
      expression {
        if (value != null && value < coonow) {
          cooobj.ObjectLock(true, true);
          cooobj.invoicestate = "IS_PAID";
        }
      }
    }
  }
}


The next example illustrates a Java method implementation of the same functionality as shown in the previous example.

Example

app.ducx Object Model Language

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class<ContentObjectClass> : ContentObject {
    date invoicepaymentdate {
      set = SetInvoiceDate;
    }
  }
}

app.ducx Use Case Language

usecases APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  SetInvoiceDate(parameters as AttrSetPrototype) {
    variant Invoice {
      java = APPDUCXSAMPLE.Invoice.SetInvoiceDate;
    }
  }
}

Java Implementation

@DUCXImplementation("APPDUCXSAMPLE@200.200:SetInvoiceDate")
public SetInvoiceDateResult SetInvoiceDate(final Object attrdef,
  final List<java.lang.Object> value, final List<java.lang.Object>
  oldvalue) throws CooException {
  SetInvoiceDateResult result = new SetInvoiceDateResult();
  Date invoicedate = (Date) value.get(0);

  if (invoicedate != null && invoicedate.before(new Date())) {
    this.COOSYSTEM_1_1_ObjectLock(true, true, null, null);
    this.APPDUCXSAMPLE_200_300_invoicestate = InvoiceState.IS_PAID;
  }

  return result;
}