public class SymbolSearchProvider extends BaseProvider {
  private static MetaField symbolQuery =
      MetaFieldFactory.createText("symbolQuery", Security.class.getSimpleName(), false);
  private static Metadata parameterMeta = Metadata.from(symbolQuery);
  private static Metadata optionalMeta = Metadata.from();
  private static SecurityMarshaller marshaller = new SecurityMarshaller();

  public SymbolSearchProvider() {
    super("SymbolSearchProvider", parameterMeta, optionalMeta, marshaller.getMetadata());
  }

  @Override
  public void produce(DataRowSet parameter, DataRowSet response, QueryConfiguration config)
      throws DataProviderException {
    int nextRow = 0;
    for (int i = 0; i < parameter.size(); i++) {
      final String id = parameter.getValueAsText(symbolQuery, i).toUpperCase();
      Collection<Security> securities =
          DaoLocator.securityDao.filter(
              new Filter<Security>() {
                @Override
                public boolean accept(Security security) {
                  return security.getSymbol().contains(id);
                }
              });
      //
      for (Security security : securities) {
        DataRowSet rowset = marshaller.marshal(security);
        nextRow = addRowSet(response, rowset, nextRow);
      }
    }
  }
}
public class PositionMarshaller implements DataRowSetMarshaller<Position> {
  private static MetaField positionId =
      MetaFieldFactory.create(
          "positionId", Position.class.getSimpleName(), MetaFieldType.SCALAR_INTEGER, true);
  private static MetaField price =
      MetaFieldFactory.createDecimal("position.price", Position.class.getSimpleName(), false);
  private static MetaField quantity =
      MetaFieldFactory.createDecimal("position.quantity", Position.class.getSimpleName(), false);
  private static Metadata responseMeta =
      Metadata.from(positionId, SharedMeta.accountId, price, quantity, SharedMeta.symbol);

  @Override
  public DataRowSet marshal(Position position) {
    DataRowSet rowset = new DataRowSet(responseMeta);
    marshal(rowset, position, 0);
    return rowset;
  }

  public DataRowSet marshal(Collection<Position> positions) {
    DataRowSet rowset = new DataRowSet(responseMeta);
    for (Position position : positions) {
      marshal(rowset, position, rowset.size());
    }
    return rowset;
  }

  private void marshal(DataRowSet rowset, Position position, int rowNum) {
    rowset.addValueAtRow(positionId, position.getId(), rowNum);
    rowset.addValueAtRow(SharedMeta.accountId, position.getAccount().getId(), rowNum);
    rowset.addValueAtRow(SharedMeta.symbol, position.getSecurity().getSymbol(), rowNum);
    rowset.addValueAtRow(price, position.getPrice(), rowNum);
    rowset.addValueAtRow(quantity, position.getQuantity(), rowNum);
  }

  @Override
  public Position unmarshal(DataRowSet rowset) {
    Position position = new Position();
    return position; // TODO fill in fields
  }

  @Override
  public Metadata getMetadata() {
    return responseMeta;
  }
}