SSIS custom destination component - Where do I Create ExternalMetaData Columns - ssis

I've created a custom SSIS destination component to write to an MQ. I'm changing the code as I go using a test SSIS package to confirm it works.
I've got it all working where it maps the Message to the input column. All good. However I'm creating the ExternalMetadataColumnCollection in ProvideComponentProperties. I only realised when I started a new test package that this is the wrong place to call it. Now when I try to add the new component to the package I get an error
Error at Data Flow Task [SSIS.Pipeline]: The property is read-only.
Error at Data Flow Task [IBM MQ Destination Jo [6]]: System.Runtime.InteropServices.COMException (0xC0204013): Exception from HRESULT: 0xC0204013
at Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSExternalMetadataColumn100.set_ID(Int32 pID)
at IBMWebsphereMQ.DestinationAdapters.IbmMQDestinationAdapter.CreateInputAndMetaDataColumns (IDTSInput100 input)
at
IBMWebsphereMQ.DestinationAdapters.IbmMQDestinationAdapter.ProvideComponentProperties()
at Microsoft.SqlServer.Dts.Pipeline.ManagedComponentHost.HostProvideComponentProperties(IDTSManagedComponentWrapper100 wrapper)
Obviously ProvideComponentProperties is not the right place to create teh ExternalMetaData columns. Where should I be calling it?
Below is the code for the component
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Transactions;
using MyProject.IBMWebsphereMQ.ConnectionManagers;
using MyProject.IBMWebsphereMQ.Framework;
using MyProject.IBMWebsphereMQ.Interfaces;
using Microsoft.SqlServer.Dts.Pipeline;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime;
using MyProject.IBMWebsphereMQ.MQ;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
namespace MyProject.IBMWebsphereMQ.DestinationAdapters
{
[DtsPipelineComponent(ComponentType = ComponentType.SourceAdapter,
DisplayName = "IBM MQ Destination Jo",
Description = "Writes messages to the defined queue",
IconResource = "Dts.Pipeline.SSISSourceAdapter.source.ico",
CurrentVersion = 1
)]
public class IbmMQDestinationAdapter : PipelineComponent, IEnlistmentNotification
{
private const string QueuePropertyName = "Queue";
private const string BatchWriteSize = "BatchWriteSize";
private const string ConnectionName = "IBM MQ connection";
private const string MessageInputName = "Message";
private const string ColumnName = "Message";
private const string InputDescription = "Input for IbmMQDestinationAdapter";
private IManagedConnection connection;
private IQueue queue;
private ArrayList columnInfos = new ArrayList();
private bool reRaise = true;
private IDTSInput100 messageInput;
#region ColumnInfo
private struct ColumnInfo
{
public int BufferColumnIndex;
public string ColumnName;
}
#endregion
private string QueueName
{
get { return GetProperty<string>(QueuePropertyName); }
}
private int BatchSize
{
get { return GetProperty<int>(BatchWriteSize); }
}
public override void ProvideComponentProperties()
{
TraceLogging.WriteTrace(this, "Executing ProvideComponentProperties");
//base.ProvideComponentProperties();
////Clear out base implementation
//ComponentMetaData.RuntimeConnectionCollection.RemoveAll();
//ComponentMetaData.InputCollection.RemoveAll();
//ComponentMetaData.OutputCollection.RemoveAll();
//Provide the inital components.
RemoveAllInputsOutputsAndCustomProperties();
ComponentMetaData.RuntimeConnectionCollection.RemoveAll();
ComponentMetaData.UsesDispositions = true;
SetComponentAttribute();
messageInput = ComponentMetaData.InputCollection.New();
messageInput.Name = MessageInputName;
messageInput.Description = InputDescription;
messageInput.HasSideEffects = true;
messageInput.ExternalMetadataColumnCollection.IsUsed = true;
TraceLogging.WriteTrace(this, "Creating InputColCollection");
IDTSInputColumn100 inCol = messageInput.InputColumnCollection.New();
TraceLogging.WriteTrace(this, "Setting incol.Name {0}" , ColumnName);
inCol.Name = ColumnName;
CreateInputAndMetaDataColumns(messageInput);
DtsExtensions.CreateCustomProperty(ComponentMetaData.CustomPropertyCollection.New(), QueuePropertyName, "The name of the queue to connect to", true, "QueueName");
//DtsExtensions.CreateCustomProperty(ComponentMetaData.CustomPropertyCollection.New(), BatchWriteSize, "Maximum number of messages to dequeue(0=all)", true, 5000);
//Reserve space for the connection manager
IDTSRuntimeConnection100 connectionSite = ComponentMetaData.RuntimeConnectionCollection.New();
connectionSite.Name = ConnectionName;
}
public override DTSValidationStatus Validate()
{
bool pbCancel = false;
if (ComponentMetaData.OutputCollection.Count != 0)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, "Unexpected Output found. Destination components do not support outputs",
"", 0, out pbCancel);
return DTSValidationStatus.VS_ISCORRUPT;
}
if (ComponentMetaData.AreInputColumnsValid == false)
{
ComponentMetaData.InputCollection["ComponentInput"].InputColumnCollection.RemoveAll();
return DTSValidationStatus.VS_NEEDSNEWMETADATA;
}
////What about if we have input columns but we have no ExternalMetaData
////columns? Maybe somebody removed them through code.
//IDTSInput100 input = ComponentMetaData.InputCollection[MessageInputName];
//if (DoesEachInputColumnHaveAMetaDataColumnAndDoDatatypesMatch(input.ID) ==false)
//{
// ComponentMetaData.FireError(0, "Validate", "input columns and metadata columns are out of sync. Making call to ReinitializeMetaData", "", 0, out pbCancel);
// return DTSValidationStatus.VS_NEEDSNEWMETADATA;
//}
return base.Validate();
}
private bool DoesEachInputColumnHaveAMetaDataColumnAndDoDatatypesMatch(int inputID)
{
IDTSInput100 input = ComponentMetaData.InputCollection.GetObjectByID(inputID);
IDTSExternalMetadataColumn100 mdc;
bool rtnVal = true;
foreach (IDTSInputColumn100 col in input.InputColumnCollection)
{
if (col.ExternalMetadataColumnID == 0)
{
rtnVal = false;
}
else
{
mdc =
input.ExternalMetadataColumnCollection[col.ExternalMetadataColumnID];
if (mdc.DataType != col.DataType || mdc.Length != col.Length ||
mdc.Precision != col.Precision || mdc.Scale != col.Scale || mdc.CodePage !=
col.CodePage)
{
rtnVal = false;
}
}
}
return rtnVal;
}
public override void OnInputPathAttached(int inputID)
{
IDTSInput100 input = ComponentMetaData.InputCollection.GetObjectByID(inputID);
IDTSVirtualInput100 vInput = input.GetVirtualInput();
foreach (IDTSVirtualInputColumn100 vCol in vInput.VirtualInputColumnCollection)
{
this.SetUsageType(inputID, vInput, vCol.LineageID, DTSUsageType.UT_READONLY);
}
}
public override void PreExecute()
{
TraceLogging.WriteTrace(this, "PreExecute");
IDTSInput100 input = ComponentMetaData.InputCollection[MessageInputName];
// CreateInputAndMetaDataColumns(input );
TraceLogging.WriteTrace(this, "PreExecute after getting Inputcollection");
ComponentMetaData.FireInformation(0, "PreExecute about to loop", "Start loop of columns", null, 0, ref reRaise);
TraceLogging.WriteTrace(this, "PreExecute Loop");
foreach (IDTSInputColumn100 inCol in input.InputColumnCollection)
{
ColumnInfo ci = new ColumnInfo();
ci.BufferColumnIndex = BufferManager.FindColumnByLineageID(input.Buffer, inCol.LineageID);
ci.ColumnName = inCol.Name;
TraceLogging.WriteTrace(this, " PreExecute columnInfo Name: {0}", inCol.Name);
columnInfos.Add(ci);
}
}
public override void ReinitializeMetaData()
{
IDTSInput100 _profinput = ComponentMetaData.InputCollection[MessageInputName];
if (_profinput.ExternalMetadataColumnCollection.Count > 0)
{
_profinput.ExternalMetadataColumnCollection.RemoveAll();
}
if (_profinput.InputColumnCollection.Count > 0)
{
_profinput.InputColumnCollection.RemoveAll();
}
CreateMetaDataColumns(_profinput);
}
private void CreateMetaDataColumns(IDTSInput100 input)
{
TraceLogging.WriteTrace(this, "CreateMetaDataColumns");
IDTSExternalMetadataColumnCollection100 extCols = input.ExternalMetadataColumnCollection;
TraceLogging.WriteTrace(this, "Got extCols");
//IDTSInputColumn100 inCol = messageInput.InputColumnCollection.New();
//inCol.Name = ColumnName;
foreach (IDTSInputColumn100 inCol in input.InputColumnCollection)
{
TraceLogging.WriteTrace(this, "For Each ColumnName = {0}", inCol.Name);
if (inCol.Name == ColumnName)
{
TraceLogging.WriteTrace(this, "Create new ExtCol");
IDTSExternalMetadataColumn100 extCol = extCols.New();
TraceLogging.WriteTrace(this, "Set them to input col");
extCol.Name = inCol.Name;
extCol.ID = inCol.ID;
extCol.DataType = inCol.DataType;
extCol.Length = inCol.Length;
extCol.Precision = inCol.Precision;
extCol.Scale = inCol.Scale;
extCol.CodePage = inCol.CodePage;
}
}
}
public override void AcquireConnections(object transaction)
{
if (transaction != null && connection.Configuration.AcknowledgementMode == Acknowledgement.Session)
{
ComponentMetaData.FireInformation(0, "AcquireConnections()", "Enlist in transaction", null, 0,
ref reRaise);
//If the connection mode is session and there is a valid transaction then enlist.
IntPtr pUnk = Marshal.GetIUnknownForObject(transaction);
var dtcTrans = (IDtcTransaction)Marshal.GetTypedObjectForIUnknown(pUnk, typeof(IDtcTransaction));
Transaction managedTrans = TransactionInterop.GetTransactionFromDtcTransaction(dtcTrans);
managedTrans.EnlistVolatile(this, EnlistmentOptions.EnlistDuringPrepareRequired);
}
IDTSRuntimeConnection100 conn = ComponentMetaData.RuntimeConnectionCollection[0];
connection = (IManagedConnection)conn.ConnectionManager.AcquireConnection(transaction);
if (connection is IbmMQConnection)
{
ComponentMetaData.FireInformation(0, "AcquireConnections()", "Connecting", null, 0, ref reRaise);
//Connect if not connected
if (!connection.IsConnected())
connection.Connect();
if (connection.IsConnected())
{
ComponentMetaData.FireInformation(0, "AcquireConnections()", "Connected.", null, 0, ref reRaise);
ComponentMetaData.FireInformation(0, "AcquireConnections()", "Connecting to queue", null, 0, ref reRaise);
queue = new IbmMQQueue(connection) { QueueName = QueueName };
queue.Open();
}
}
}
public override void ReleaseConnections()
{
if (queue != null)
queue.Close();
base.ReleaseConnections();
}
//public void CreateExternalMetaDataColumn(IDTSInput100 input, int inputColumnID)
//{
// IDTSInputColumn100 oColumn = input.InputColumnCollection.GetObjectByID(inputColumnID);
// IDTSExternalMetadataColumn100 eColumn = input.ExternalMetadataColumnCollection.New();
// eColumn.DataType = oColumn.DataType;
// eColumn.Precision = oColumn.Precision;
// eColumn.Scale = oColumn.Scale;
// eColumn.Length = oColumn.Length;
// eColumn.CodePage = oColumn.CodePage;
// oColumn.ExternalMetadataColumnID = eColumn.ID;
//}
public override void ProcessInput(int inputID, PipelineBuffer buffer)
{
ComponentMetaData.FireInformation(0, "ProcessInput Jo", "Beginning Process Input", null, 0, ref reRaise);
if (!buffer.EndOfRowset)
{
while (buffer.NextRow())
{
ComponentMetaData.FireInformation(0, "ProcessInput()", "Beginning loop of columnns", null, 0,
ref reRaise);
TraceLogging.WriteTrace(this, "Process Input columninfos,count = {0}", columnInfos.Count);
var message = new Message();
for (int i = 0; i < columnInfos.Count; i++)
{
ColumnInfo ci = (ColumnInfo) columnInfos[i];
object o = buffer[ci.BufferColumnIndex];
if (o == null)
{
TraceLogging.WriteTrace(this, "o is null");
TraceLogging.WriteTrace(this, "ColumnName: {0} ", ci.ColumnName);
}
else
{
TraceLogging.WriteTrace(this, "testing trace {0}: ", "Jo");
TraceLogging.WriteTrace(this, "ColumnName: {0}", ci.ColumnName);
TraceLogging.WriteTrace(this, "Column Value: {0}", buffer[ci.BufferColumnIndex].ToString());
if (ci.ColumnName == ColumnName)
{
TraceLogging.WriteTrace(this, "Setting MessageContents");
message.Contents = buffer[ci.BufferColumnIndex].ToString();
}
else
{
TraceLogging.WriteTrace(this, "Setting MessageId");
message.MessageId = buffer[ci.BufferColumnIndex].ToString();
}
}
}
queue.Write(message);
//string messageContents = buffer.GetString(m_BlobColumnIndex);
//TraceLogging.WriteTrace(this, "Message contents", messageContents);
//var message = new Message("1", messageContents);
//ComponentMetaData.FireInformation(0, "ProcessInput()", "Beginning queue write set contents", null, 0,
// ref reRaise);
//queue.Write(message);
ComponentMetaData.FireInformation(0, "ProcessInput()", "after queue write", null, 0, ref reRaise);
connection.Commit();
}
}
}
private void SetComponentAttribute()
{
var componentAttribute =
(DtsPipelineComponentAttribute)
Attribute.GetCustomAttribute(GetType(), typeof(DtsPipelineComponentAttribute), false);
int currentVersion = componentAttribute.CurrentVersion;
ComponentMetaData.Version = currentVersion;
ComponentMetaData.ContactInfo = ContactInfo;
}
private T GetProperty<T>(string propertyName)
{
foreach (IDTSCustomProperty100 possibleProperty in ComponentMetaData.CustomPropertyCollection)
{
if (possibleProperty.Name == propertyName)
{
return (T)possibleProperty.Value;
}
}
return default(T);
}
#region IEnlistmentNotification Members
public void Commit(Enlistment enlistment)
{
ComponentMetaData.FireInformation(0, "Commit(Enlistment enlistment)", "Beginning commit", null, 0, ref reRaise);
connection.Commit();
ComponentMetaData.FireProgress("Committed", 100, 0, 0, "IbmMQSourceAdapter", ref reRaise);
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
}
public void Prepare(PreparingEnlistment preparingEnlistment)
{
if (connection != null)
{
preparingEnlistment.Prepared();
// TraceLogging.WriteTrace(this, "Transaction Preparing");
}
}
public void Rollback(Enlistment enlistment)
{
connection.Rollback();
// TraceLogging.WriteTrace(this, "Rollback Executed");
ComponentMetaData.FireWarning(0, "Rollback(Enlistment enlistment)", "Rolling back transaction", null, 0);
enlistment.Done();
}
#endregion
}
}

Related

vala: Serializing object property with Json.gobject_serialize?

I need to save an object's state into a file and retrieve it later. I found JSON serialization would help and found this method Json.gobject_serialize. Using this method, I can successfully serialize objects containing string properties. But what should I do, if the object A consists of another object (say B) within it and I need to serialize object A.
EDIT
What should I do if the object A consists of array (say B) of objects?
I created a small test program for this purpose and I failed in that try. I cannot find any detailed documentation about JSON Serialization for vala.
public class Foo : Object {
public int iFoo {get; set;}
public string sFoo {get; set;}
Bar[] _bar = {};
public Bar[] bar {get {return _bar;} set{_bar = value;}}
public class Bar : Object {
public int iBar {get; set;}
public string sBar {get; set;}
construct {
iBar = 02;
sBar = "OutOfRange";
}
}
construct {
_bar += new Bar();
iFoo = 74;
sFoo = "GIrafee";
}
public static int main () {
Json.Node root = Json.gobject_serialize (new Foo());
Json.Generator generator = new Json.Generator ();
generator.set_root (root);
stdout.printf(generator.to_data (null) + "\n");
return 0;
}
}
Serialization with JSON-GLib is recursive for properties containing complex types.
If the property of a GObject contains another GObject, json_gobject_serialize() will recursively call json_gobject_serialize() on the instance stored inside the property — or serialize the null if the property is unset.
I've implemented a object to support Json.Serializable interface as follow:
public class DbObject : GLib.Object, Json.Serializable
{
public Json.Object? meta { get; construct set; default = null; }
public VersionSync version { get; set; default = VersionSync.UNKNOWN; }
public virtual Value get_property (ParamSpec pspec)
{
Value prop_value = GLib.Value(pspec.value_type);
(this as GLib.Object).get_property(pspec.name, ref prop_value);
stdout.printf ("%s --> %s\n", prop_value.type_name(), prop_value.strdup_contents());
return prop_value;
}
public virtual void set_property (ParamSpec pspec, Value value)
{
(this as GLib.Object).set_property (pspec.name, value);
}
public unowned ParamSpec? find_property (string name)
{
return ((ObjectClass) get_type ().class_ref ()).find_property (name);
}
public virtual Json.Node serialize_property (string property_name, Value #value, ParamSpec pspec)
{
if (#value.type ().is_a (typeof (Json.Object)))
{
var obj = #value as Json.Object;
if (obj != null)
{
var node = new Json.Node (NodeType.OBJECT);
node.set_object (obj);
return node;
}
}
else if (#value.type ().is_a (typeof (Gee.ArrayList)))
{
unowned Gee.ArrayList<GLib.Object> list_value = #value as Gee.ArrayList<GLib.Object>;
if (list_value != null || property_name == "data")
{
var array = new Json.Array.sized (list_value.size);
foreach (var item in list_value)
{
array.add_element (gobject_serialize (item));
}
var node = new Json.Node (NodeType.ARRAY);
node.set_array (array);
return node;
}
}
else if (#value.type ().is_a (typeof (GLib.Array)))
{
unowned GLib.Array<GLib.Object> array_value = #value as GLib.Array<GLib.Object>;
if (array_value != null || property_name == "data")
{
var array = new Json.Array.sized (array_value.length);
for (int i = 0; i < array_value.length; i++) {
array.add_element (gobject_serialize (array_value.index(i)));
}
var node = new Json.Node (NodeType.ARRAY);
node.set_array (array);
return node;
}
}
else if (#value.type ().is_a (typeof (HashTable)))
{
var obj = new Json.Object ();
var ht_string = #value as HashTable<string, string>;
if (ht_string != null)
{
ht_string.foreach ((k, v) => {
obj.set_string_member (k, v);
});
var node = new Json.Node (NodeType.OBJECT);
node.set_object (obj);
return node;
} else {
var ht_object = #value as HashTable<string, GLib.Object>;
if (ht_object != null)
{
ht_object.foreach ((k, v) => {
obj.set_member (k, gobject_serialize (v));
});
var node = new Json.Node (NodeType.OBJECT);
node.set_object (obj);
return node;
}
}
}
return default_serialize_property (property_name, #value, pspec);
}
public virtual bool deserialize_property (string property_name, out Value #value, ParamSpec pspec, Json.Node property_node)
{
return default_deserialize_property (property_name, out #value, pspec, property_node);
}
}

JSP tag library to display MySQL rollup query with grouping and subtotals

I need to display several tables as HTML, using JSP, coming from MySQL GROUP BY a,b,c WITH ROLLUP queries. I'm looking for a good tag library to achieve this. I have found DisplayTag, but it'was last updated in 2008. And I would prefer using the subtotals calculated by MySQL, which seems to be tricky with DisplayTag.
MySQL does subtotals by adding extra rows to the resultset with the group field set to NULL.
Is there a better alternative? Printing the table is important, paging and sorting would be nice but I can live without them. No editing of any kind.
I wrote my own quick-and-dirty tag. Note that it expects the rollup data structure returned by MySQL, haven't tested it with anything else.
Usage example:
<xxx:rollupTable cssClass="data" data="${data}">
<xxx:rollupColumn title="Person" align="left" group="true" fieldName="personName" groupFieldName="personId" tooltipLink="person"/>
<xxx:rollupColumn title="City" align="left" group="true" fieldName="cityName" groupFieldName="cityId" tooltipLink="city"/>
<xxx:rollupColumn title="Price" align="right" format="#,##0.000" fieldName="price"/>
<xxx:rollupColumn title="Amount" align="right" format="#,##0" fieldName="amount"/>
</xxx:rollupTable>
The column tag does not much but adds the column definition to the table tag for later use.
package xxx.tags;
import...
public class RollupTableColumnTag extends SimpleTagSupport {
private String title;
private boolean group = false;
private boolean sum = false;
private String fieldName; // field name to output
private String groupFieldName; // field name to test for rollup level changes
private String align;
private String format;
private String tooltipLink;
private DecimalFormat formatter;
public void doTag() throws IOException, JspTagException {
RollupTableTag parent = (RollupTableTag)findAncestorWithClass(this, RollupTableTag.class);
if (parent == null) {
throw new JspTagException("Parent tag not found.");
}
parent.addColumnDefinition(this);
}
public void setFormat(String format) {
formatter = new DecimalFormat(format);
this.format = format;
}
public DecimalFormat getFormatter() {
return formatter;
}
// other getters and setters are standard, excluded
}
The table tag does the actual hard work:
package xxx.tags;
import ...
public class RollupTableTag extends BodyTagSupport {
protected String cssClass;
protected List<Map> data;
protected List<RollupTableColumnTag> columns;
protected List<Integer> groups;
public void setCssClass(String cssClass) {
this.cssClass = cssClass;
}
public void setData(List data) {
this.data = (List<Map>)data;
}
public int doStartTag() throws JspException {
columns = new ArrayList<RollupTableColumnTag>();
groups = new ArrayList<Integer>();
return EVAL_BODY_BUFFERED;
}
public int doEndTag() throws JspException {
try {
JspWriter writer = pageContext.getOut();
if (data.size() == 0) {
writer.println("<P>No data.</P>");
return EVAL_PAGE;
}
int nLevels = groups.size();
int nNormalRowCount = 0;
boolean[] bStartGroup = new boolean[nLevels];
String[] sSummaryTitle = new String[nLevels];
for (int i=0;i<nLevels;i++) {
bStartGroup[i] = true;
}
writer.println("<TABLE class=\"" + cssClass + "\">");
writer.println("<THEAD><TR>");
for (RollupTableColumnTag column : columns) {
writer.print("<TH");
if (column.getAlign() != null) {
writer.print(" align=\"" + column.getAlign() + "\"");
}
writer.print(">" + column.getTitle() + "</TH>");
}
writer.println("</TR></THEAD>");
writer.println("<TBODY>");
for (Map dataRow : data) {
StringBuffer out = new StringBuffer();
out.append("<TR>");
// grouping columns always come first
String cellClass = null;
for (int i=0;i<nLevels-1;i++) {
if (bStartGroup[i]) {
Object dataField = dataRow.get(columns.get(groups.get(i)).getFieldName());
sSummaryTitle[i] = dataField == null ? "" : dataField.toString();
}
}
int nLevelChanges = 0;
for (int i=0;i<nLevels;i++) {
if (dataRow.get( columns.get(groups.get(i)).getGroupFieldName() ) == null) {
if (i>0) {
bStartGroup[i-1] = true;
}
nLevelChanges++;
}
}
int nTotalLevel = nLevels - nLevelChanges;
if (nLevelChanges == nLevels) { // grand total row
cellClass = "grandtotal";
addCell(out, "Grand Total:", null, cellClass, nLevelChanges);
} else if (nLevelChanges > 0) { // other total row
boolean isOneLiner = (nNormalRowCount == 1);
nNormalRowCount = 0;
if (isOneLiner) continue; // skip one-line sums
cellClass = "total"+nTotalLevel;
for (int i=0;i<nLevels-nLevelChanges-1;i++) {
addCell(out," ",null,cellClass, 1);
}
addCell(out, sSummaryTitle[nLevels-nLevelChanges-1] + " total:", null, cellClass, nLevelChanges+1);
} else { // normal row
for (int i=0;i<nLevels;i++) {
if (bStartGroup[i]) {
RollupTableColumnTag column = columns.get(groups.get(i));
Object cellData = dataRow.get(column.getFieldName());
String displayVal = cellData != null ? cellData.toString() : "[n/a]";
if (column.getTooltipLink() != null && !column.getTooltipLink().isEmpty() && cellData != null) {
String tooltip = column.getTooltipLink();
int dataid = Integer.parseInt(dataRow.get(column.getGroupFieldName()).toString());
displayVal = "<div ajaxtooltip=\"" + tooltip + "\" ajaxtooltipid=\"" + dataid + "\">" + displayVal + "</div>";
}
addCell(out, displayVal, column.getAlign(), null, 1);
} else {
addCell(out," ", null, null, 1);
}
}
for (int i=0;i<nLevels-1;i++) {
bStartGroup[i] = false;
}
nNormalRowCount++;
}
// other columns
for (RollupTableColumnTag column : columns) {
if (!column.isGroup()) {
Object content = dataRow.get(column.getFieldName());
String displayVal = "";
if (content != null) {
if (column.getFormat() != null) {
float val = Float.parseFloat(content.toString());
displayVal = column.getFormatter().format(val);
} else {
displayVal = content.toString();
}
}
addCell(out,displayVal,column.getAlign(),cellClass,1);
}
}
out.append("</TR>");
// empty row for better readability
if (groups.size() > 2 && nLevelChanges == groups.size() - 1) {
out.append("<TR><TD colspan=\"" + columns.size() + "\"> </TD>");
}
writer.println(out);
}
writer.println("</TBODY>");
writer.println("</TABLE>");
} catch (IOException e) {
e.printStackTrace();
}
return EVAL_PAGE;
}
public void addCell(StringBuffer out, String content, String align, String cssClass, int colSpan) {
out.append("<TD");
if (align != null) {
out.append(" align=\"" + align + "\"");
}
if (cssClass != null) {
out.append(" class=\"" + cssClass + "\"");
}
if (colSpan > 1) {
out.append(" colspan=\"" + colSpan + "\"");
}
out.append(">");
out.append(content);
out.append("</TD>");
}
public void addColumnDefinition(RollupTableColumnTag cd) {
columns.add(cd);
if (cd.isGroup()) groups.add(columns.size()-1);
}
}

Having difficulty creating an array of Json objects for use in a Kendo grid

I need to convert a server response from an array to an array of JSON object format.
The rows of data coming fron the server needs to be converted in order for the Kendo UI grid widget to work properly.
I have converted the schema and column definitions into a Json format, but having some difficulty with the actual data rows.
Here's the RAW server response where
1) the "data" array contains the data schema
2) the "rows" array contains the actual values :
{"status":"SUCCESS", "messages":[],
"data":[{"attributes":[{"name":"BookingLocation","type":"string"},{"name":"SUM(CDSStress A:USD 10Y X -1.25)","type":"double"},{"name":"SUM(CDSStress A:USD 10Y X 1.25)","type":"double"},{"name":"SUM(CDSStress A:USD 8Y X 1.25)","type":"double"}],
"rows":[{"id":0,"values":["London",0,0,0]},{"id":1,"values":["Paris",0,0,0]},{"id":2,"values":["Dubai",1564.92711931719,-171.934775655824,-54539.9112355565]},{"id":3,"values":["New York",0,0,0]},{"id":4,"values":["Stockholm",0,0,0]},{"id":5,"values":["World",0,0,0]}]}]}
Essentially I need to pull the "attributes" array, and match them up with the "rows" array - and do this all dynamically for any server response.
Now pulling the schema information from the "attributes" array (within "data"), I can build the schema JSON object dynamically, then plug it into the Kendo grid - something like this :
var myModel = { // sample schema object; actually built dynamically in javascript
"id": "Id",
"fields": {
"BookingCountry": {
"type": "string"
},
"SUM(CDSStress A:USD 10Y X -1.25)": {
"type": "number"
},
"SUM(CDSStress A:USD 10Y X 1.25)": {
"type": "number"
},
"SUM(CDSStress A:USD 8Y X 1.25)": {
"type": "number"
}
}
}
var myColumns = $rootScope.reptWizard.colDefs; // build the columns def
var myData = $rootScope.reptWizard.aggrResults; // convert data rows to JSON object
var ds = {
schema: {
model: myModel
},
vm.mainHierGridOptions = {
dataSource: ds,
columns: myColumns
};
pageSize: 10,
data: myData
};
{
However, the 'myData' object needs to look like this :
[
{ "id": 0,
"BookingCountry": "London",
"SUM(CDSStress A:USD 10Y X -1.25)": 1564.92711,
"SUM(CDSStress A:USD 10Y X 1.25)": -171.9347756,
"SUM(CDSStress A:USD 8Y X 1.25)": -54539.911235
},
{ "id": 0,
"BookingCountry": "Dubai",
"SUM(CDSStress A:USD 10Y X -1.25)": 1564.92711,
"SUM(CDSStress A:USD 10Y X 1.25)": -171.9347756,
"SUM(CDSStress A:USD 8Y X 1.25)": -54539.911235
}
]
As you can see, I need to iterate the "values" array and create a nicely-formatted JSON object with the correct field:value - i.e. "BookingCountry": "London".
Here's a function I created to format the myCols var :
function buildDynamicColumnDefs(fieldAttribs) {
// creates an array of Json objects; to be used as input to the Grid's 'columns' property
var numAttribs = fieldAttribs.length;
var myType = '';
var myCols = [];
if (numAttribs > 0) {
_.each(fieldAttribs, function (field) {
myCols.push({field: field, title: field});
});
}
return myCols;
}
and another function to create the myModel var :
function buildDynamicDataSourceModel(fieldAttribs) {
// creates a valid Json object {name:value} to be used in Kendo Grid DataSource
var jsonExample = {
"BookingLocation": { "type": "string" },
"SUM(CDSStress A:USD 10Y X -1.25)": { "type": "number" },
"SUM(CDSStress A:USD 10Y X 1.25)": { "type": "number" },
"SUM(CDSStress A:USD 8Y X 1.25)": { "type": "number" }
};
var numAttribs = fieldAttribs.length;
var myType = '';
var myFields = {};
if (numAttribs > 0) {
_.each(fieldAttribs, function (field) {
myType = (field.type == "double" ? "number" : field.type); // 'number' is valid type for Kendo Grid schema
myFields[field.name] = { type: myType };
});
}
var myModel = {
id: "Id",
fields: myFields
/*fields: {
dimensions: { type: "string" },
values: { editable: false, type: "number" }
}*/
};
return myModel;
}
But now I need to create the buildJSONGridData(), and your help is greatly appreciated.
regards,
Bob
Here is a function I used to help in exporting a Kendo UI Grid to pdf and Reporting services . This function takes the client blob values (title,columns,data) and build a collection ofg strongly types objects. You could probally do the same on the client side. Notice where the if(dataObject!=null) is located that is where the data json objects are deserialzed. Hope it helps.
//------------------------------------------------------------------------------------------------------------------------------------
private CustomReportData CreateReportFromKendoData(string title, string columns, string data)
{
List<int> _ignoredColumns=new List<int>();
var columnObject = (columns == null) ? null : JsonConvert.DeserializeObject<dynamic>(columns);
var dataObject = (data == null) ? null : JsonConvert.DeserializeObject<dynamic>(data);
CustomReportData reportData = new CustomReportData();
reportData.ReportTitle = title;
if (columnObject != null)
for (int columnCount = 0; columnCount < columnObject.Count; columnCount++)
{
string fieldName = columnObject[columnCount].title == null ? columnObject[columnCount].field.ToString() : columnObject[columnCount].title.ToString();
if (ShouldDisplay(columnObject[columnCount].ToString()))
{
//IF WIDTH IS NULL THEN COLUMNS ARE EVNLY SPREAD THIS WILL BOMB
reportData.Columns.Add(new CustomReportColumn
{
FieldName = fieldName,
DataType = "",
Width = (columnObject[columnCount].width!=null)?this.GetFirstNumeric(columnObject[columnCount].width.ToString(), 250) :250
});
}
else
_ignoredColumns.Add(columnCount);
}
if (dataObject != null)
{
bool hasGrouping = dataObject[0].value != null;
for (int rowCount = 0; rowCount < dataObject.Count; rowCount++)
{
if (hasGrouping)
{
CustomReportGroup group = new CustomReportGroup();
group.GroupName = dataObject[rowCount].field.ToString();
group.GroupValue = ApplyFormat(dataObject[rowCount].value.ToString(),null);
this.RecursiveProcessGroups(group, dataObject[rowCount].items.ToString(), columnObject.ToString(),_ignoredColumns);
reportData.Groups.Add(group);
}
else
{
CustomReportDataRow row = new CustomReportDataRow();
for (int columnCount = 0; columnCount < columnObject.Count; columnCount++)
{
if (!_ignoredColumns.Contains(columnCount))
{
string format = (columnObject[columnCount].format == null ? "" : columnObject[columnCount].format.ToString());
string value = dataObject[rowCount][columnObject[columnCount].field.ToString()].ToString();
value = ApplyFormat(value, format);
row.Fields.Add(value);
}
}
reportData.DataRows.Add(row);
}
}
reportData.GroupDepth = this.GetGroupDepth(reportData.Groups);
}
return reportData;
}
Recursive function for group nesting
//------------------------------------------------------------------------------------------------------------------------------------
private void RecursiveProcessGroups(CustomReportGroup parentGroup, string items, string columns, List<int> ignoredColumns)
{
var groupItems = (items == null) ? null : JsonConvert.DeserializeObject<dynamic>(items);
var columnObject = (columns == null) ? null : JsonConvert.DeserializeObject<dynamic>(columns);
bool hasGrouping = groupItems[0]["value"] != null;
if (hasGrouping)
{
for (int rowCount = 0; rowCount < groupItems.Count; rowCount++)
{
CustomReportGroup group = new CustomReportGroup();
group.GroupName = groupItems[rowCount].field.ToString();
group.GroupValue = ApplyFormat(groupItems[rowCount].value.ToString(),null);
parentGroup.Groups.Add(group);
RecursiveProcessGroups(group, groupItems[rowCount].items.ToString(), columns.ToString(), ignoredColumns);
}
}
else
{
for (int groupItemCount = 0; groupItemCount < groupItems.Count; groupItemCount++)
{
CustomReportDataRow row = new CustomReportDataRow();
for (int columnCount = 0; columnCount < columnObject.Count; columnCount++)
if (!ignoredColumns.Contains(columnCount))
{
string value = groupItems[groupItemCount][columnObject[columnCount].field.ToString()].ToString();
string format = (columnObject[columnCount].format == null ? "" : columnObject[columnCount].format.ToString());
value = ApplyFormat(value, format);
row.Fields.Add(value);
}
parentGroup.DataRows.Add(row);
}
}
}
Domain Objects
public class CustomReportColumn
{
public string FieldName { get; set; }
public string DataType { get; set; }
public float Width { get; set; }
}
public class CustomReportColumns : List<CustomReportColumn> { }
public class CustomReportDataRow
{
public CustomReportDataRow()
{
Fields = new List<string>();
}
public List<string> Fields { get; set; }
}
public class CustomReportDataRows : List<CustomReportDataRow> { }
public class CustomReportGroup
{
public CustomReportGroup()
{
DataRows = new CustomReportDataRows();
Groups = new CustomReportGroups();
}
public string GroupName { get; set; }
public string GroupValue { get; set; }
public CustomReportGroups Groups { get; set; }
public CustomReportDataRows DataRows { get; set; }
}
public class CustomReportGroups : List<CustomReportGroup> { }
public class CustomReportData
{
public CustomReportData()
{
Groups = new CustomReportGroups();
Columns = new CustomReportColumns();
DataRows = new CustomReportDataRows();
}
public int GroupDepth { get; set; }
public CustomReportColumns Columns { get; set; }
public CustomReportGroups Groups { get; set; }
public CustomReportDataRows DataRows { get; set; }
public string ReportTitle { get; set; }
}
PDF Conversion
using iTextSharp.text;
using iTextSharp.text.pdf;
using Svg;
public class PDFServiceiTextSharp:IPDFService
{
private int _GroupDepth=0;
private int _ColumnCount = 0;
//-----------------------------------------------------------------------------------------------------------------------------------------
public byte[] RenderCustomReport(CustomReportData data)
{
try
{
using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("INMEMORYPDF.pdf", 1000000))
{
PDFPageMargins margins = new PDFPageMargins(10, 10, 10, 10);
_GroupDepth = data.GroupDepth;
_ColumnCount = data.Columns.Count;
float _pageWidth = this.GetPageWidth(data.Columns, margins);
var document=new Document((_pageWidth>540)?PageSize.A4.Rotate(): PageSize.A4, margins.Left,margins.Right, margins.Top, margins.Bottom);
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
PdfWriter.GetInstance(document, stream);
document.Open();
var pdfTable = new PdfPTable(_ColumnCount + _GroupDepth);
int[] columnWidths = new int[_ColumnCount + _GroupDepth];
for(int x=0;x<_GroupDepth;x++)
columnWidths[x]=3;
for(int y=0;y<data.Columns.Count;y++)
columnWidths[_GroupDepth + y] = Convert.ToInt32(data.Columns[y].Width);
pdfTable.SetWidths(columnWidths);
pdfTable.DefaultCell.Padding = 3;
pdfTable.DefaultCell.BorderWidth = 1;
pdfTable.DefaultCell.HorizontalAlignment = Element.ALIGN_TOP;
this.CreateHeaderColumns(pdfTable, data.Columns);
pdfTable.HeaderRows = 1;
pdfTable.DefaultCell.BorderWidth = 1;
if (data.Groups.Count > 0)
this.CreateGroupData(pdfTable, data.Groups, 0);
else
for (int x = 0; x < data.DataRows.Count; x++)
this.CreateDetailColumns(pdfTable, data.DataRows[x]);
document.Add(pdfTable);
document.Close();
}
byte[] content;
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
BinaryReader rdr = new BinaryReader(stream);
content = new byte[mmf.CreateViewStream().Length];
rdr.Read(content, 0, (int)mmf.CreateViewStream().Length);
}
return content;
}
}
catch
{
throw;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
public float GetPageWidth(CustomReportColumns columns, PDFPageMargins margins)
{
float width=0;
foreach (CustomReportColumn c in columns)
width += c.Width;
return width + margins.Left + margins.Right + (_GroupDepth * 3);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateHeaderColumns(PdfPTable table,CustomReportColumns columns)
{
Font headerFont = this.GetHeaderFont();
for(int gc=0;gc<_GroupDepth;gc++)
{
PdfPCell cell = new PdfPCell(new Phrase("", headerFont));
cell.BorderWidth=0;
table.AddCell(cell);
}
for (int x = 0; x < columns.Count; x++)
{
PdfPCell cell = new PdfPCell(new Phrase(columns[x].FieldName, headerFont));
cell.BorderColor = new BaseColor(100, 149, 237);
cell.HorizontalAlignment = Element.ALIGN_CENTER;
cell.BorderWidth=0.75f;
cell.Border = Rectangle.BOTTOM_BORDER | Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.LEFT_BORDER;
cell.PaddingBottom = 10;
cell.PaddingLeft = 3;
cell.PaddingRight = 3;
cell.PaddingTop = 10;
table.AddCell(cell);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateGroupData(PdfPTable table, CustomReportGroups parentgroups, int groupDepth)
{
if ((parentgroups == null)||(parentgroups.Count==0))
return;
groupDepth++;
foreach (CustomReportGroup group in parentgroups)
{
this.CreateGroupHeader(table, group, groupDepth);
for (int x = 0; x < group.DataRows.Count; x++)
this.CreateDetailColumns(table, group.DataRows[x]);
CreateGroupData(table, group.Groups, groupDepth);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateDetailColumns(PdfPTable table, CustomReportDataRow row)
{
Font detailFont = this.GetDetailFont();
for (int gc = 1; gc <= _GroupDepth; gc++)
{
BaseColor groupColor = this.GetGroupHeaderColor(_GroupDepth);
PdfPCell cell = new PdfPCell(new Phrase("", detailFont));
cell.BackgroundColor = groupColor;
cell.BorderColor = groupColor;
cell.BorderWidth = 0.75f;
table.AddCell(cell);
}
for (int x = 0; x < row.Fields.Count; x++)
{
PdfPCell cell = new PdfPCell(new Phrase(row.Fields[x], detailFont));
cell.BorderColor = new BaseColor(211, 211, 211);
cell.HorizontalAlignment = Element.ALIGN_CENTER;
cell.BorderWidth = 0.75f;
cell.Border = Rectangle.BOTTOM_BORDER | Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.LEFT_BORDER;
cell.PaddingBottom = 1;
cell.PaddingLeft = 3;
cell.PaddingRight = 3;
cell.PaddingTop = 1;
table.AddCell(cell);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateGroupHeader(PdfPTable table, CustomReportGroup group, int depth)
{
Font detailFont = this.GetDetailFont();
for (int gc = 1; gc <= _GroupDepth; gc++)
{
BaseColor depthColor = this.GetGroupHeaderColor(depth);
PdfPCell ecell = new PdfPCell(new Phrase("", detailFont));
ecell.BackgroundColor = depthColor;
ecell.BorderColor = depthColor;
ecell.BorderWidth = 0.75f;
table.AddCell(ecell);
}
BaseColor groupColor = this.GetGroupHeaderColor(depth);
PdfPCell cell = new PdfPCell(new Phrase( group.GroupValue, detailFont));
cell.Colspan = _ColumnCount + ((_GroupDepth - depth));
cell.BorderColor = groupColor;
cell.BackgroundColor = groupColor;
cell.HorizontalAlignment = Element.ALIGN_LEFT;
cell.BorderWidth = 0.75f;
cell.Border = Rectangle.BOTTOM_BORDER | Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.LEFT_BORDER;
cell.PaddingBottom = 3;
cell.PaddingLeft = 3;
cell.PaddingRight = 3;
cell.PaddingTop = 3;
table.AddCell(cell);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private Font GetHeaderFont()
{
return FontFactory.GetFont("Arial", 10, Font.BOLD, BaseColor.BLACK);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private Font GetDetailFont()
{
return FontFactory.GetFont("Arial", 8, Font.NORMAL, BaseColor.BLACK);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private BaseColor GetGroupHeaderColor(int groupDepth)
{
switch (groupDepth)
{
case 1: return new BaseColor(211,211,211);
case 2: return new BaseColor(100, 149, 237);
case 3: return new BaseColor(255,165,0);
case 4: return new BaseColor(169,169,169);
case 5: return new BaseColor(211, 211, 211);
default: return new BaseColor(211, 211, 211);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
public void MergeFiles(System.Collections.Generic.List<string> sourceFiles, string destinationFile)
{
Document document=null;
if (System.IO.File.Exists(destinationFile))
System.IO.File.Delete(destinationFile);
try
{
PdfCopy writer = null;
int numberOfPages=0;
foreach(string sourceFile in sourceFiles)
{
PdfReader reader = new PdfReader(sourceFile);
reader.ConsolidateNamedDestinations();
numberOfPages = reader.NumberOfPages;
if(document==null)
{
document = new Document(reader.GetPageSizeWithRotation(1));
writer = new PdfCopy(document, new FileStream(destinationFile, FileMode.Create));
document.Open();
}
for (int x = 1;x <= numberOfPages;x++ )
{
if (writer != null)
{
PdfImportedPage page = writer.GetImportedPage(reader, x);
writer.AddPage(page);
}
}
PRAcroForm form = reader.AcroForm;
if (form != null && writer != null)
{
writer.CopyAcroForm(reader);
}
}
}
catch
{
throw;
}
finally
{
if (document != null && document.IsOpen())
document.Close();
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
public byte[] RenderReportFromSVG(string svgFileContents)
{
System.Drawing.Bitmap _bitmap=null;
byte[] byteArray = Encoding.ASCII.GetBytes(svgFileContents);
using (var stream = new MemoryStream(byteArray))
{
XmlDocument xdoc=new XmlDocument();
xdoc.LoadXml(svgFileContents);
var svgDocument = SvgDocument.Open(xdoc);
_bitmap = svgDocument.Draw();
}
using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("INMEMORYPDF.pdf", 1000000))
{
PDFPageMargins margins = new PDFPageMargins(10, 10, 10, 10);
float _pageWidth = margins.Left + margins.Right + _bitmap.Width;
var document = new Document((_pageWidth > 540) ? PageSize.A4.Rotate() : PageSize.A4, margins.Left, margins.Right, margins.Top, margins.Bottom);
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
PdfWriter.GetInstance(document, stream);
document.Open();
iTextSharp.text.Image pdfImage = iTextSharp.text.Image.GetInstance(_bitmap, System.Drawing.Imaging.ImageFormat.Bmp);
var pdfTable = new PdfPTable(1);
pdfTable.SetWidths(new int[]{_bitmap.Width});
pdfTable.DefaultCell.HorizontalAlignment = Element.ALIGN_TOP;
PdfPCell cell = new PdfPCell(pdfImage);
//cell.FixedHeight = fixedHeight;
cell.HorizontalAlignment = Element.ALIGN_CENTER;
cell.VerticalAlignment = Element.ALIGN_MIDDLE;
//img.ScaleAbsolute(200, fixedHeight);
pdfTable.AddCell(cell);
document.Add(pdfTable);
document.Close();
}
byte[] content;
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
BinaryReader rdr = new BinaryReader(stream);
content = new byte[mmf.CreateViewStream().Length];
rdr.Read(content, 0, (int)mmf.CreateViewStream().Length);
}
return content;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
}
Finally the ExcelService to render grid to excel with column groupings
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
public class ExcelServiceNPOI:IExcelService
{
//-----------------------------------------------------------------------------------------------------------------------------------------
public byte[] RenderCustomReport(CustomReportData data)
{
try
{
if (data == null)
throw new ArgumentNullException("Report data cannot be null");
HSSFWorkbook workBook = new HSSFWorkbook();
ISheet sheet = workBook.CreateSheet(data.ReportTitle);
if (data.Groups.Count > 0)
{
int maxDepth = data.GroupDepth;// this.GroupDepth(data.Groups, 0);
this.CreateColumnHeader(sheet,maxDepth, data.Columns );
this.CreateGroupData(sheet, data.Groups, 0, maxDepth);
}
else
{
this.CreateColumnHeader(sheet, data.Columns);
this.CreateRowData(sheet, data.DataRows);
}
this.SetColumnWidth(sheet, data.Columns);
sheet.CreateFreezePane(0, 1);
MemoryStream ms = new MemoryStream();
workBook.Write(ms);
return ms.ToArray();
}
catch
{
throw;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateColumnHeader(ISheet sheet,CustomReportColumns columns)
{
this.CreateColumnHeader(sheet, 0, columns);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateColumnHeader(ISheet sheet, int columnOffset, CustomReportColumns columns )
{
if (columns == null || columns.Count == 0)
return;
IRow headerRow = sheet.CreateRow(0);
int colCount = columnOffset;
foreach (CustomReportColumn column in columns)
{
headerRow.CreateCell(colCount).SetCellValue(column.FieldName);
colCount++;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateGroupData(ISheet sheet, CustomReportGroups parentgroups,int groupDepth, int maxDepth)
{
if (parentgroups == null)
return;
groupDepth++;
foreach (CustomReportGroup group in parentgroups)
{
CustomReportDataRow groupHeader = new CustomReportDataRow();
groupHeader.Fields.Add(group.GroupValue);
this.CreateRowData(sheet,groupDepth-1, groupHeader);
int groupBeginRowNum = sheet.LastRowNum+1;
this.CreateRowData(sheet,maxDepth, group.DataRows);
CreateGroupData(sheet,group.Groups, groupDepth, maxDepth);
sheet.GroupRow(groupBeginRowNum, sheet.LastRowNum);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateRowData(ISheet sheet, int startColumnIndex, CustomReportDataRow row)
{
int colNum = startColumnIndex;
IRow newRow = sheet.CreateRow(sheet.LastRowNum + 1);
foreach (string field in row.Fields)
newRow.CreateCell(colNum++).SetCellValue(field);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateRowData(ISheet sheet, CustomReportDataRows rows)
{
CreateRowData(sheet, 0, rows);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateRowData(ISheet sheet, int startColumnIndex, CustomReportDataRows rows)
{
foreach (CustomReportDataRow row in rows)
{
int colNum = startColumnIndex;
IRow newRow = sheet.CreateRow(sheet.LastRowNum + 1);
foreach (string field in row.Fields)
newRow.CreateCell(colNum++).SetCellValue(field);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void SetColumnWidth(ISheet sheet, CustomReportColumns columns)
{
if (columns == null || columns.Count == 0)
return;
for (int x = 0; x < columns.Count;x++ )
sheet.AutoSizeColumn(x);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
}
Feel free to use it. It works with the latest version of Kendo. I have also added a function RenderReportFromSVG() It will print a Kendo Chart to pdf using chart.svgContents

PrimeFaces 5.0 datatable filter case sensitive

In PrimeFaces 5.0, datatable filter is case sensitive. In Primefaces 4 the filter was not case sensitive. But now in 5.0 my app doesn't work.
DataTable Filtering v. 5.0.1
Filtering is case sensitive in 5.0, due to feedback it is now case insensitive. FilterEvent was also providing wrong information about the filters, it has been corrected as well.
http://blog.primefaces.org/?p=3184
You can use the filterFunction option, like this:
In XHTML:
<p:column ...
filterBy="#{car.name}"
filterFunction="#{carListView.filterByName}"
In View:
public boolean filterByName(Object value, Object filter, Locale locale) {
String filterText = (filter == null) ? null : filter.toString().trim();
if (filterText == null || filterText.equals("")) {
return true;
}
if (value == null) {
return false;
}
String carName = value.toString().toUpperCase();
filterText = filterText.toUpperCase();
if (carName.contains(filterText)) {
return true;
} else {
return false;
}
}
This worked for me. Please refer to: http://www.primefaces.org/showcase/ui/data/datatable/filter.xhtml (price column). And also page 153 at the PrimeFaces 5.0 manual (pdf).
I have been facing the same problem.
But I fix it replacing the filter class of primefaces.
1- create a package in you project: org.primefaces.component.datatable.feature
2 - create a class: FilterFeature
I've included this part on the class:
// FIX bug primefaces 5.0
// The filter should be case insensitive
if(columnValue != null && filterValue!= null){
columnValue = columnValue.toString().toUpperCase();
filterValue = filterValue.toString().toUpperCase();
}
Copy the contents of this class to your file.
FilterFeature.java
/*
* Copyright 2009-2014 PrimeTek.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.primefaces.component.datatable.feature;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.el.ELContext;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import org.primefaces.component.api.UIColumn;
import javax.faces.component.UIComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import org.primefaces.component.api.DynamicColumn;
import org.primefaces.component.column.Column;
import org.primefaces.component.columngroup.ColumnGroup;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.component.datatable.DataTableRenderer;
import org.primefaces.component.row.Row;
import org.primefaces.context.RequestContext;
import org.primefaces.model.filter.*;
import org.primefaces.util.Constants;
public class FilterFeature implements DataTableFeature {
private final static Logger logger = Logger.getLogger(DataTable.class.getName());
private final static String STARTS_WITH_MATCH_MODE = "startsWith";
private final static String ENDS_WITH_MATCH_MODE = "endsWith";
private final static String CONTAINS_MATCH_MODE = "contains";
private final static String EXACT_MATCH_MODE = "exact";
private final static String LESS_THAN_MODE = "lt";
private final static String LESS_THAN_EQUALS_MODE = "lte";
private final static String GREATER_THAN_MODE = "gt";
private final static String GREATER_THAN_EQUALS_MODE = "gte";
private final static String EQUALS_MODE = "equals";
private final static String IN_MODE = "in";
private final static String GLOBAL_MODE = "global";
final static Map<String,FilterConstraint> FILTER_CONSTRAINTS;
static {
FILTER_CONSTRAINTS = new HashMap<String,FilterConstraint>();
FILTER_CONSTRAINTS.put(STARTS_WITH_MATCH_MODE, new StartsWithFilterConstraint());
FILTER_CONSTRAINTS.put(ENDS_WITH_MATCH_MODE, new EndsWithFilterConstraint());
FILTER_CONSTRAINTS.put(CONTAINS_MATCH_MODE, new ContainsFilterConstraint());
FILTER_CONSTRAINTS.put(EXACT_MATCH_MODE, new ExactFilterConstraint());
FILTER_CONSTRAINTS.put(LESS_THAN_MODE, new LessThanFilterConstraint());
FILTER_CONSTRAINTS.put(LESS_THAN_EQUALS_MODE, new LessThanEqualsFilterConstraint());
FILTER_CONSTRAINTS.put(GREATER_THAN_MODE, new GreaterThanFilterConstraint());
FILTER_CONSTRAINTS.put(GREATER_THAN_EQUALS_MODE, new GreaterThanEqualsFilterConstraint());
FILTER_CONSTRAINTS.put(EQUALS_MODE, new EqualsFilterConstraint());
FILTER_CONSTRAINTS.put(IN_MODE, new InFilterConstraint());
FILTER_CONSTRAINTS.put(GLOBAL_MODE, new GlobalFilterConstraint());
}
private boolean isFilterRequest(FacesContext context, DataTable table) {
return context.getExternalContext().getRequestParameterMap().containsKey(table.getClientId(context) + "_filtering");
}
public boolean shouldDecode(FacesContext context, DataTable table) {
return false;
}
public boolean shouldEncode(FacesContext context, DataTable table) {
return isFilterRequest(context, table);
}
public void decode(FacesContext context, DataTable table) {
String globalFilterParam = table.getClientId(context) + UINamingContainer.getSeparatorChar(context) + "globalFilter";
List<FilterMeta> filterMetadata = this.populateFilterMetaData(context, table);
Map<String,Object> filterParameterMap = this.populateFilterParameterMap(context, table, filterMetadata, globalFilterParam);
table.setFilters(filterParameterMap);
table.setFilterMetadata(filterMetadata);
}
public void encode(FacesContext context, DataTableRenderer renderer, DataTable table) throws IOException {
//reset state
updateFilteredValue(context, table, null);
table.setFirst(0);
table.setRowIndex(-1);
if(table.isLazy()) {
table.loadLazyData();
}
else {
String globalFilterParam = table.getClientId(context) + UINamingContainer.getSeparatorChar(context) + "globalFilter";
filter(context, table, table.getFilterMetadata(), globalFilterParam);
//sort new filtered data to restore sort state
boolean sorted = (table.getValueExpression("sortBy") != null || table.getSortBy() != null);
if(sorted) {
SortFeature sortFeature = (SortFeature) table.getFeature(DataTableFeatureKey.SORT);
if(table.isMultiSort())
sortFeature.multiSort(context, table);
else
sortFeature.singleSort(context, table);
}
}
renderer.encodeTbody(context, table, true);
}
private void filter(FacesContext context, DataTable table, List<FilterMeta> filterMetadata, String globalFilterParam) {
Map<String,String> params = context.getExternalContext().getRequestParameterMap();
List filteredData = new ArrayList();
Locale filterLocale = table.resolveDataLocale();
boolean hasGlobalFilter = params.containsKey(globalFilterParam);
String globalFilterValue = hasGlobalFilter ? params.get(globalFilterParam): null;
GlobalFilterConstraint globalFilterConstraint = (GlobalFilterConstraint) FILTER_CONSTRAINTS.get(GLOBAL_MODE);
ELContext elContext = context.getELContext();
for(int i = 0; i < table.getRowCount(); i++) {
table.setRowIndex(i);
boolean localMatch = true;
boolean globalMatch = false;
for(FilterMeta filterMeta : filterMetadata) {
Object filterValue = filterMeta.getFilterValue();
UIColumn column = filterMeta.getColumn();
MethodExpression filterFunction = column.getFilterFunction();
ValueExpression filterByVE = filterMeta.getFilterByVE();
if(column instanceof DynamicColumn) {
((DynamicColumn) column).applyStatelessModel();
}
Object columnValue = filterByVE.getValue(elContext);
FilterConstraint filterConstraint = this.getFilterConstraint(column);
// FIX bug primefaces 5.0
// The filter should be case insensitive
if(columnValue != null && filterValue!= null){
columnValue = columnValue.toString().toUpperCase();
filterValue = filterValue.toString().toUpperCase();
}
if(hasGlobalFilter && !globalMatch) {
globalMatch = globalFilterConstraint.applies(columnValue, globalFilterValue, filterLocale);
}
if(filterFunction != null) {
localMatch = (Boolean) filterFunction.invoke(elContext, new Object[]{columnValue, filterValue, filterLocale});
}
else if(!filterConstraint.applies(columnValue, filterValue, filterLocale)) {
localMatch = false;
}
if(!localMatch) {
break;
}
}
boolean matches = localMatch;
if(hasGlobalFilter) {
matches = localMatch && globalMatch;
}
if(matches) {
filteredData.add(table.getRowData());
}
}
//Metadata for callback
if(table.isPaginator()) {
RequestContext requestContext = RequestContext.getCurrentInstance();
if(requestContext != null) {
requestContext.addCallbackParam("totalRecords", filteredData.size());
}
}
//save filtered data
updateFilteredValue(context, table, filteredData);
table.setRowIndex(-1); //reset datamodel
}
public void updateFilteredValue(FacesContext context, DataTable table, List<?> value) {
table.setSelectableDataModelWrapper(null);
ValueExpression ve = table.getValueExpression("filteredValue");
if(ve != null) {
ve.setValue(context.getELContext(), value);
}
else {
if(value != null) {
logger.log(Level.WARNING, "DataTable {0} has filtering enabled but no filteredValue model reference is defined"
+ ", for backward compatibility falling back to page viewstate method to keep filteredValue."
+ " It is highly suggested to use filtering with a filteredValue model reference as viewstate method is deprecated and will be removed in future."
, new Object[]{table.getClientId(context)});
}
table.setFilteredValue(value);
}
}
private Map<String,Object> populateFilterParameterMap(FacesContext context, DataTable table, List<FilterMeta> filterMetadata, String globalFilterParam) {
Map<String,String> params = context.getExternalContext().getRequestParameterMap();
Map<String,Object> filterParameterMap = new HashMap<String, Object>();
for(FilterMeta filterMeta : filterMetadata) {
Object filterValue = filterMeta.getFilterValue();
UIColumn column = filterMeta.getColumn();
if(filterValue != null && !filterValue.toString().trim().equals(Constants.EMPTY_STRING)) {
String filterField = null;
ValueExpression filterByVE = column.getValueExpression("filterBy");
if(column.isDynamic()) {
((DynamicColumn) column).applyStatelessModel();
Object filterByProperty = column.getFilterBy();
String field = column.getField();
if(field == null)
filterField = (filterByProperty == null) ? table.resolveDynamicField(filterByVE) : filterByProperty.toString();
else
filterField = field;
}
else {
String field = column.getField();
if(field == null)
filterField = (filterByVE == null) ? (String) column.getFilterBy(): table.resolveStaticField(filterByVE);
else
filterField = field;
}
filterParameterMap.put(filterField, filterValue);
}
}
if(params.containsKey(globalFilterParam)) {
filterParameterMap.put("globalFilter", params.get(globalFilterParam));
}
return filterParameterMap;
}
private List<FilterMeta> populateFilterMetaData(FacesContext context, DataTable table) {
List<FilterMeta> filterMetadata = new ArrayList<FilterMeta>();
String separator = String.valueOf(UINamingContainer.getSeparatorChar(context));
String var = table.getVar();
Map<String,String> params = context.getExternalContext().getRequestParameterMap();
ColumnGroup group = getColumnGroup(table, "header");
if(group != null) {
for(UIComponent child : group.getChildren()) {
Row headerRow = (Row) child;
if(headerRow.isRendered()) {
for(UIComponent headerRowChild : headerRow.getChildren()) {
Column column = (Column) headerRowChild;
if(column.isRendered()) {
ValueExpression columnFilterByVE = column.getValueExpression("filterBy");
Object filterByProperty = column.getFilterBy();
if(columnFilterByVE != null || filterByProperty != null) {
ValueExpression filterByVE = (columnFilterByVE != null) ? columnFilterByVE : createFilterByVE(context, var, filterByProperty);
UIComponent filterFacet = column.getFacet("filter");
Object filterValue;
if(filterFacet == null)
filterValue = params.get(column.getClientId(context) + separator + "filter");
else
filterValue = ((ValueHolder) filterFacet).getLocalValue();
filterMetadata.add(new FilterMeta(column, filterByVE, filterValue));
}
}
}
}
}
}
else {
for(UIColumn column : table.getColumns()) {
ValueExpression columnFilterByVE = column.getValueExpression("filterBy");
Object filterByProperty = column.getFilterBy();
if (columnFilterByVE != null || filterByProperty != null) {
UIComponent filterFacet = column.getFacet("filter");
Object filterValue = null;
ValueExpression filterByVE = null;
String filterId = null;
if(column instanceof Column) {
filterByVE = (columnFilterByVE != null) ? columnFilterByVE : createFilterByVE(context, var, filterByProperty);
filterId = column.getClientId(context) + separator + "filter";
}
else if(column instanceof DynamicColumn) {
DynamicColumn dynamicColumn = (DynamicColumn) column;
dynamicColumn.applyStatelessModel();
filterByProperty = column.getFilterBy();
filterByVE = (filterByProperty == null) ? columnFilterByVE : createFilterByVE(context, var, filterByProperty);
filterId = dynamicColumn.getContainerClientId(context) + separator + "filter";
dynamicColumn.cleanStatelessModel();
}
if(filterFacet == null)
filterValue = params.get(filterId);
else
filterValue = ((ValueHolder) filterFacet).getLocalValue();
filterMetadata.add(new FilterMeta(column, filterByVE, filterValue));
}
}
}
return filterMetadata;
}
private ColumnGroup getColumnGroup(DataTable table, String target) {
for(UIComponent child : table.getChildren()) {
if(child instanceof ColumnGroup) {
ColumnGroup colGroup = (ColumnGroup) child;
String type = colGroup.getType();
if(type != null && type.equals(target)) {
return colGroup;
}
}
}
return null;
}
public FilterConstraint getFilterConstraint(UIColumn column) {
String filterMatchMode = column.getFilterMatchMode();
FilterConstraint filterConstraint = FILTER_CONSTRAINTS.get(filterMatchMode);
if(filterConstraint == null) {
throw new FacesException("Illegal filter match mode:" + filterMatchMode);
}
return filterConstraint;
}
private ValueExpression createFilterByVE(FacesContext context, String var, Object filterBy) {
ELContext elContext = context.getELContext();
return context.getApplication().getExpressionFactory().createValueExpression(elContext, "#{" + var + "." + filterBy + "}", Object.class);
}
private class FilterMeta {
private UIColumn column;
private ValueExpression filterByVE;
private Object filterValue;
public FilterMeta(UIColumn column, ValueExpression filterByVE, Object filterValue) {
this.column = column;
this.filterByVE = filterByVE;
this.filterValue = filterValue;
}
public UIColumn getColumn() {
return column;
}
public ValueExpression getFilterByVE() {
return filterByVE;
}
public Object getFilterValue() {
return filterValue;
}
}
}
I took a little more simplistic approach to get past this in my situation.
In my XHTML:
<p:column filterBy="#{car.nameLowercase}" sortBy="#{car.name}"
filterMatchMode="contains">
<h:outputText value="#{car.name}"/>
</p:column>
In my car bean I simply add a getter:
public String getNameLowerCase() {
if (name == null) {
return null;
}
return name.toLowerCase();
}
This seems to work for my purposes. Hope it will help you!
I had same issue on the Lazy.xhtml, I fixied it by go to the LazyCarDataModel.java, on load method, change
if(filterValue==null ||
fieldvalue.startswith(filtervalue.toString()))
to
if(filterValue==null ||
fieldvalue.startswith(filtervalue.toString().toLowerCase() ||
fieldvalue.startswith(filtervalue.toString().toUpperCase()) )

How to Seed DB after DontDropDbJustCreateTablesIfModelChanged

Recently I've had my DB rights reduced so that I can't drop and recreate databases. This has led to me using the DontDropDbJustCreateTablesIfModelChanged Database initialisation from nuget.
However I'm now stuck as to how I should seed data as the Seed function is not in the initialisation so I can't override it. This is what I'd like to be able to do.
public class MyDBInitialiser : DontDropDbJustCreateTablesIfModelChanged<MyContext>
{
protected override void Seed(MyContext context)
{
base.Seed(context);
context.Item.Add(new Item() { ItemId = 1, Name = "Item 1"});
context.Item.Add(new Item() { ItemId = 2, Name = "Item 2"});
context.Item.Add(new Item() { ItemId = 3, Name = "Item 3"});
}
}
Is there another way of seeding data in this situation.
Simply,
public class DontDropDbJustCreateTablesIfModelChanged<T>
: IDatabaseInitializer<T> where T : DbContext
{
private EdmMetadata _edmMetaData;
public void InitializeDatabase(T context)
{
ObjectContext objectContext =
((IObjectContextAdapter)context).ObjectContext;
string modelHash = GetModelHash(objectContext);
if (CompatibleWithModel(modelHash, context, objectContext))
return;
DeleteExistingTables(objectContext);
CreateTables(objectContext);
SaveModelHashToDatabase(context, modelHash, objectContext);
Seed(context);
}
protected virtual void Seed(T context) { }
private void SaveModelHashToDatabase(T context, string modelHash,
ObjectContext objectContext)
{
if (_edmMetaData != null) objectContext.Detach(_edmMetaData);
_edmMetaData = new EdmMetadata();
context.Set<EdmMetadata>().Add(_edmMetaData);
_edmMetaData.ModelHash = modelHash;
context.SaveChanges();
}
private void CreateTables(ObjectContext objectContext)
{
string dataBaseCreateScript =
objectContext.CreateDatabaseScript();
objectContext.ExecuteStoreCommand(dataBaseCreateScript);
}
private void DeleteExistingTables(ObjectContext objectContext)
{
objectContext.ExecuteStoreCommand(Dropallconstraintsscript);
objectContext.ExecuteStoreCommand(Deletealltablesscript);
}
private string GetModelHash(ObjectContext context)
{
var csdlXmlString = GetCsdlXmlString(context).ToString();
return ComputeSha256Hash(csdlXmlString);
}
private bool CompatibleWithModel(string modelHash, DbContext context,
ObjectContext objectContext)
{
var isEdmMetaDataInStore =
objectContext.ExecuteStoreQuery<int>(LookupEdmMetaDataTable)
.FirstOrDefault();
if (isEdmMetaDataInStore == 1)
{
_edmMetaData = context.Set<EdmMetadata>().FirstOrDefault();
if (_edmMetaData != null)
{
return modelHash == _edmMetaData.ModelHash;
}
}
return false;
}
private string GetCsdlXmlString(ObjectContext context)
{
if (context != null)
{
var entityContainerList = context.MetadataWorkspace
.GetItems<EntityContainer>(DataSpace.SSpace);
if (entityContainerList != null)
{
var entityContainer = entityContainerList.FirstOrDefault();
var generator =
new EntityModelSchemaGenerator(entityContainer);
var stringBuilder = new StringBuilder();
var xmlWRiter = XmlWriter.Create(stringBuilder);
generator.GenerateMetadata();
generator.WriteModelSchema(xmlWRiter);
xmlWRiter.Flush();
return stringBuilder.ToString();
}
}
return string.Empty;
}
private static string ComputeSha256Hash(string input)
{
byte[] buffer = new SHA256Managed()
.ComputeHash(Encoding.ASCII.GetBytes(input));
var builder = new StringBuilder(buffer.Length * 2);
foreach (byte num in buffer)
{
builder.Append(num.ToString("X2",
CultureInfo.InvariantCulture));
}
return builder.ToString();
}
private const string Dropallconstraintsscript =
#"select
'ALTER TABLE ' + so.table_name + ' DROP CONSTRAINT '
+ so.constraint_name
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS so";
private const string Deletealltablesscript =
#"declare #cmd varchar(4000)
declare cmds cursor for
Select
'drop table [' + Table_Name + ']'
From
INFORMATION_SCHEMA.TABLES
open cmds
while 1=1
begin
fetch cmds into #cmd
if ##fetch_status != 0 break
print #cmd
exec(#cmd)
end
close cmds
deallocate cmds";
private const string LookupEdmMetaDataTable =
#"Select COUNT(*)
FROM INFORMATION_SCHEMA.TABLES T
Where T.TABLE_NAME = 'EdmMetaData'";
}
&
public class Population : DontDropDbJustCreateTablesIfModelChanged</* DbContext */>
{
protected override void Seed(Syndication Context)
{
/* Seeding :) */
}
}
&
Database.SetInitializer</* DbContext */>(new Population());
I my projects I split the db initialization from the db seeding. If you use inversion of control, you should be able to do something like this in your composition root (Application_Start if you are consuming the DbContext from a web app):
var seeder = ServiceLocatorPattern
.ServiceProviderLocator.Current.GetService<ISeedDb>();
if (seeder != null) seeder.Seed();
The interface:
public interface ISeedDb, IDisposable
{
void Seed();
}
A possible implementation:
public class MyDbSeeder : ISeedDb
{
private readonly MyContext _context;
public MyDbSeeder(MyContext context)
{
_context = context;
}
public void Seed()
{
_context.Item.Add(new Item { ItemId = 1, Name = "Item 1" });
// ... etc
}
public void Dispose()
{
_context.Dispose();
}
}