Author: heiko.braun(a)jboss.com
Date: 2010-03-30 10:41:06 -0400 (Tue, 30 Mar 2010)
New Revision: 1022
Added:
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/TimespanValues.java
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/public/monitor.css
Modified:
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/App.gwt.xml
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/DebugPanel.java
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/DefinitionHistoryView.java
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/server/ChartDataService.java
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/DefaultBPAFDataSource.java
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/metric/Grouping.java
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/metric/Timespan.java
Log:
added timespan selection, first cut
Modified:
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/App.gwt.xml
===================================================================
---
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/App.gwt.xml 2010-03-30
08:48:19 UTC (rev 1021)
+++
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/App.gwt.xml 2010-03-30
14:41:06 UTC (rev 1022)
@@ -11,6 +11,7 @@
<inherits name="org.jboss.errai.bus.ErraiBus"/>
<inherits name="org.jboss.errai.workspaces.ErraiWorkspaces" />
+ <stylesheet src="monitor.css"/>
<entry-point class='org.jboss.bpm.monitor.gui.client.MonitorUI'/>
</module>
\ No newline at end of file
Modified:
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/DebugPanel.java
===================================================================
---
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/DebugPanel.java 2010-03-30
08:48:19 UTC (rev 1021)
+++
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/DebugPanel.java 2010-03-30
14:41:06 UTC (rev 1022)
@@ -3,11 +3,11 @@
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.gen2.table.event.client.RowSelectionEvent;
-import com.google.gwt.gen2.table.event.client.RowSelectionHandler;
import com.google.gwt.user.client.ui.Button;
import org.gwt.mosaic.ui.client.CaptionLayoutPanel;
import org.gwt.mosaic.ui.client.ListBox;
+import org.gwt.mosaic.ui.client.event.RowSelectionEvent;
+import org.gwt.mosaic.ui.client.event.RowSelectionHandler;
import org.gwt.mosaic.ui.client.layout.BoxLayout;
import org.gwt.mosaic.ui.client.layout.BoxLayoutData;
import org.gwt.mosaic.ui.client.layout.ColumnLayout;
Modified:
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/DefinitionHistoryView.java
===================================================================
---
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/DefinitionHistoryView.java 2010-03-30
08:48:19 UTC (rev 1021)
+++
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/DefinitionHistoryView.java 2010-03-30
14:41:06 UTC (rev 1022)
@@ -2,11 +2,17 @@
package org.jboss.bpm.monitor.gui.client;
import com.google.gwt.core.client.GWT;
-import com.google.gwt.event.dom.client.ChangeEvent;
-import com.google.gwt.event.dom.client.ChangeHandler;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.ListBox;
-import org.gwt.mosaic.ui.client.layout.BoxLayout;
-import org.gwt.mosaic.ui.client.layout.LayoutPanel;
+import org.gwt.mosaic.ui.client.*;
+import org.gwt.mosaic.ui.client.layout.*;
+import org.gwt.mosaic.ui.client.util.ResizableWidget;
+import org.gwt.mosaic.ui.client.util.ResizableWidgetCollection;
import org.jboss.errai.bus.client.api.RemoteCallback;
import org.jboss.errai.bus.client.api.base.MessageBuilder;
import org.jboss.errai.workspaces.client.api.ProvisioningCallback;
@@ -18,6 +24,7 @@
import org.timepedia.chronoscope.client.browser.Chronoscope;
import org.timepedia.chronoscope.client.browser.json.GwtJsonDataset;
import org.timepedia.chronoscope.client.browser.json.JsonDatasetJSO;
+import org.timepedia.chronoscope.client.canvas.View;
import org.timepedia.chronoscope.client.data.tuple.Tuple2D;
import java.util.List;
@@ -34,56 +41,154 @@
private static volatile double GOLDEN__RATIO = 1.618;
- private LayoutPanel panel;
- private ListBox listBox;
private ChartPanel chartPanel;
+ private ToolButton menuButton;
+ private ToolButton timespanButton;
+ private HTML title;
+ private HTML timespan;
+ private CaptionLayoutPanel chartArea;
+ private LayoutPanel timespanPanel;
public void provideWidget(ProvisioningCallback callback)
{
- panel = new LayoutPanel(new BoxLayout(BoxLayout.Orientation.VERTICAL));
+
+ LayoutPanel panel = new LayoutPanel(new BoxLayout(BoxLayout.Orientation.VERTICAL));
- listBox = new ListBox();
- panel.add(listBox);
- listBox.addItem("Select a process");
- listBox.addChangeHandler(new ChangeHandler()
+ final ToolBar toolBar = new ToolBar();
+ panel.add(toolBar, new BoxLayoutData(BoxLayoutData.FillStyle.HORIZONTAL));
+
+ // -----
+
+ menuButton = new ToolButton("Open");
+ menuButton.setStyle(ToolButton.ToolButtonStyle.MENU);
+ final Command selectProcessCmd = new Command() {
+ public void execute()
+ {
+ // update if necessary
+ selectDefinition();
+ }
+ };
+
+ PopupMenu menuBtnMenu = new PopupMenu();
+ menuBtnMenu.addItem("ProcessDefintion", selectProcessCmd);
+ menuButton.setMenu(menuBtnMenu);
+ toolBar.add(menuButton);
+
+ // -----
+
+ toolBar.addSeparator();
+ toolBar.add(new ToolButton("Export"));
+
+ // -----
+
+ title = new HTML();
+ title.getElement().setAttribute("style", "font-size:24px;
font-weight:BOLD");
+
+ // ------------
+
+ timespanPanel = new LayoutPanel(new BoxLayout(BoxLayout.Orientation.HORIZONTAL));
+ timespan = new HTML();
+ timespan.getElement().setAttribute("style", "padding-top:2px;
color:#ccc;font-size:16px;text-align:left;");
+ timespanButton = new ToolButton();
+ timespanButton.setVisible(false);
+ timespanButton.setStyle(ToolButton.ToolButtonStyle.MENU);
+
+ final PopupMenu timeBtnMenu = new PopupMenu();
+
+ for(final String ts : TimespanValues.ALL)
{
- public void onChange(ChangeEvent changeEvent)
+ timeBtnMenu.addItem(ts, new Command()
{
- ChartData rpcService = MessageBuilder.createCall(
- new RemoteCallback<String>()
- {
- public void callback(String response)
- {
- renderChart(response);
- }
- },
- ChartData.class
- );
-
- if(listBox.getSelectedIndex()>0)
+ public void execute()
{
- String processDefinitionID = listBox.getItemText(listBox.getSelectedIndex());
- rpcService.getDefinitionActivity(processDefinitionID, "Last 7
Days");
+ loadGraphData(title.getText(), ts);
}
- }
- });
+ });
+ };
- loadDefinitions();
+ timespanButton.setMenu(timeBtnMenu);
+ timespanPanel.add(timespanButton);
+ timespanPanel.add(timespan, new BoxLayoutData(BoxLayoutData.FillStyle.HORIZONTAL));
+
+ // ------------
+
+ LayoutPanel contents = new LayoutPanel(new RowLayout());
+ LayoutPanel headerPanel = new LayoutPanel(new ColumnLayout());
+ headerPanel.add(title, new ColumnLayoutData("50%"));
+ headerPanel.add(timespanPanel, new ColumnLayoutData("50%"));
+
+ // ------------
+
+ chartArea = new CaptionLayoutPanel();
+ chartArea.setPadding(15);
+ contents.add(headerPanel, new RowLayoutData("120"));
+ contents.add(chartArea, new RowLayoutData("350", true));
+
+ panel.add(contents, new BoxLayoutData(BoxLayoutData.FillStyle.BOTH));
callback.onSuccess(panel);
}
- private void loadDefinitions()
- {
+ private void selectDefinition()
+ {
HistoryRecords rpcService = MessageBuilder.createCall(
new RemoteCallback<List<String>>()
{
public void callback(List<String> response)
{
+ final LayoutPopupPanel popup = new LayoutPopupPanel(false);
+ popup.addStyleName("soa-PopupPanel");
+
+ final ListBox listBox = new ListBox();
+ listBox.addItem("");
+
for(String s : response)
+ {
listBox.addItem(s);
+ }
+
+ // show dialogue
+ LayoutPanel p = new LayoutPanel(new
BoxLayout(BoxLayout.Orientation.VERTICAL));
+ p.add(new HTML("Which definition would like to inspect?"));
+ p.add(listBox);
+
+ // -----
+
+ LayoutPanel p2 = new LayoutPanel(new
BoxLayout(BoxLayout.Orientation.HORIZONTAL));
+ p2.add(new Button("Done", new ClickHandler() {
+ public void onClick(ClickEvent clickEvent)
+ {
+ if(listBox.getSelectedIndex()>0)
+ {
+ popup.hide();
+ String procDef = listBox.getItemText(listBox.getSelectedIndex());
+ title.setText(procDef);
+ loadGraphData(procDef, TimespanValues.LAST_7_DAYS);
+ }
+ }
+ }));
+
+ // -----
+
+ HTML html = new HTML("Cancel");
+ html.addClickHandler(new ClickHandler(){
+ public void onClick(ClickEvent clickEvent)
+ {
+ popup.hide();
+ }
+ });
+ p2.add(html, new BoxLayoutData(BoxLayoutData.FillStyle.HORIZONTAL));
+ p.add(p2);
+
+ // -----
+
+ popup.setPopupPosition(menuButton.getAbsoluteLeft()-5,
menuButton.getAbsoluteTop()+30);
+ popup.setWidget(p);
+ popup.pack();
+ popup.show();
+
}
},
HistoryRecords.class
@@ -93,6 +198,29 @@
}
+ /**
+ * Loads the chronoscope data for a particlar processdefinition
+ * @param procDefID
+ * @param timespan
+ */
+ private void loadGraphData(final String procDefID, final String timespan)
+ {
+ ChartData rpcService = MessageBuilder.createCall(
+ new RemoteCallback<String>()
+ {
+ public void callback(String response)
+ {
+ timespanButton.setVisible(true);
+ renderChart(response);
+ timespanPanel.layout();
+ }
+ },
+ ChartData.class
+ );
+
+ rpcService.getDefinitionActivity(procDefID, timespan);
+ }
+
private void renderChart(String jsonData)
{
try
@@ -105,11 +233,11 @@
// if exists remove. I don't know how to update at this point
if(chartPanel!=null)
- panel.remove(chartPanel);
+ chartArea.remove(chartPanel);
initChartPanel(dsArray);
-
- panel.layout();
+
+ chartArea.layout();
}
catch (Exception e)
{
@@ -119,13 +247,34 @@
private void initChartPanel(Dataset[] datasets)
{
- int chartWidth = 450;
+ int chartWidth = chartArea.getOffsetWidth()/2;
int chartHeight = (int) (chartWidth / GOLDEN__RATIO);
chartPanel = Chronoscope
.createTimeseriesChart(datasets, chartWidth, chartHeight);
+
+ timespan.setText(datasets[0].getRangeLabel());
- panel.add(chartPanel);
+ chartArea.add(chartPanel);
+
+ ResizableWidgetCollection.get().add(new ResizableWidget() {
+ public Element getElement() {
+ return chartPanel.getElement();
+ }
+
+ public boolean isAttached() {
+ return chartPanel.isAttached();
+ }
+
+ public void onResize(int width, int height) {
+ int chartWidth = chartArea.getOffsetWidth()/2;
+ int chartHeight = (int) (chartWidth / GOLDEN__RATIO);
+
+ // Resizing the chart once displayed currently unsupported
+ View view = chartPanel.getChart().getView();
+ view.resize(chartWidth, chartHeight);
+ }
+ });
}
private static native JsonDatasetJSO getJson(String varName) /*-{
Added:
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/TimespanValues.java
===================================================================
---
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/TimespanValues.java
(rev 0)
+++
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/client/TimespanValues.java 2010-03-30
14:41:06 UTC (rev 1022)
@@ -0,0 +1,28 @@
+/*
jboss.org */
+package org.jboss.bpm.monitor.gui.client;
+
+/**
+ * @author: Heiko Braun <hbraun(a)redhat.com>
+ * @date: Mar 30, 2010
+ */
+public interface TimespanValues
+{
+ public static final String LAST_24_HOURS = "Last 24 Hours";
+ public static final String LAST_DAY = "Last Day";
+ public static final String LAST_7_DAYS = "Last 7 Days";
+ public static final String LAST_WEEK = "Last Week";
+ public static final String LAST_4_WEEKS = "Last 4 Weeks";
+ public static final String LAST_MONTH = "Last Month";
+ public static final String LAST_3_MONTH = "Last 3 Month";
+ public static final String LAST_QUARTER = "Last Quarter";
+ public static final String LAST_12_MONTH = "Last 12 Month";
+ public static final String LAST_YEAR = "Last Year";
+
+ public static String[] ALL = new String[] {
+ LAST_24_HOURS, LAST_DAY,
+ LAST_7_DAYS, LAST_WEEK,
+ LAST_4_WEEKS, LAST_MONTH,
+ LAST_3_MONTH, LAST_QUARTER,
+ LAST_12_MONTH, LAST_YEAR
+ };
+}
Added:
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/public/monitor.css
===================================================================
---
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/public/monitor.css
(rev 0)
+++
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/public/monitor.css 2010-03-30
14:41:06 UTC (rev 1022)
@@ -0,0 +1,9 @@
+.soa-PopupPanel {
+ border: 1px solid #e3e3e3;
+ padding: 3px;
+ background: white;
+ -moz-box-shadow: 3px 3px 3px #ccc;
+ -webkit-box-shadow: 3px 3px 3px #ccc;
+ box-shadow: 3px 3px 3px #ccc;
+
+}
\ No newline at end of file
Modified:
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/server/ChartDataService.java
===================================================================
---
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/server/ChartDataService.java 2010-03-30
08:48:19 UTC (rev 1021)
+++
activity-monitor/trunk/gui/war/src/main/java/org/jboss/bpm/monitor/gui/server/ChartDataService.java 2010-03-30
14:41:06 UTC (rev 1022)
@@ -40,13 +40,19 @@
List<Event> events = dataSource.getDefinitionEvents(processDefiniton,
timespan);
- SortedMap<Date, List<Event>> grouped;
+ SortedMap<Date, List<Event>> grouped;
switch (timespan.getUnit())
{
case DAY:
grouped = Grouping.byDay(events, timespan);
break;
+ case WEEK:
+ grouped = Grouping.byWeek(events, timespan);
+ break;
+ case MONTH:
+ grouped = Grouping.byMonth(events, timespan);
+ break;
default:
throw new IllegalArgumentException("UNIT not supported:
"+timespan.getUnit());
@@ -68,7 +74,7 @@
dataSet.getDomain().add(domainData);
dataSet.getRange().add(rangeData);
dataSet.setAxis("date");
-
+
return dataSet.toJSO();
}
}
Modified:
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/DefaultBPAFDataSource.java
===================================================================
---
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/DefaultBPAFDataSource.java 2010-03-30
08:48:19 UTC (rev 1021)
+++
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/DefaultBPAFDataSource.java 2010-03-30
14:41:06 UTC (rev 1022)
@@ -141,6 +141,7 @@
}
});
+ System.out.println(timespan.getTitle() +": "+ result.size());
return result;
}
Modified:
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/metric/Grouping.java
===================================================================
---
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/metric/Grouping.java 2010-03-30
08:48:19 UTC (rev 1021)
+++
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/metric/Grouping.java 2010-03-30
14:41:06 UTC (rev 1022)
@@ -14,38 +14,38 @@
*/
public class Grouping
{
- public static SortedMap<Date, List<Event>> byDay(List<Event> events,
Timespan timespan)
+ private static SortedMap<Date,List<Event>> _doSort(List<Event>
events, Timespan timespan, int calMetric)
{
long s0 = System.currentTimeMillis();
SortedMap<Date, List<Event>> slotCount = new TreeMap<Date,
List<Event>>();
- // create daily slots first
+ // create slots first
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timespan.getStart());
while(cal.getTimeInMillis()<timespan.getEnd())
{
slotCount.put(new Date(cal.getTimeInMillis()), new ArrayList<Event>()); //
left inclusive
- cal.roll(Calendar.DAY_OF_YEAR, 1);
+ cal.add(calMetric, 1);
}
// sort events according to slots
final Set<Date> startingDates = slotCount.keySet();
- Iterator<Date> it = startingDates.iterator();
- while(it.hasNext())
+ Iterator<Date> leftOffset = startingDates.iterator();
+ while(leftOffset.hasNext())
{
- Date from = it.next();
+ Date from = leftOffset.next();
for(Event e : events)
{
cal.setTime(from);
- cal.roll(Calendar.DAY_OF_YEAR, 1);
+ cal.add(calMetric, 1);
Date to = cal.getTime();
Date actual = new Date(e.getTimestamp());
if(actual.after(from) && actual.before(to))
{
- slotCount.get(from).add(e);
+ slotCount.get(from).add(e);
}
}
@@ -55,4 +55,19 @@
return slotCount;
}
+ public static SortedMap<Date, List<Event>> byDay(List<Event> events,
Timespan timespan)
+ {
+ return _doSort(events, timespan, Calendar.DAY_OF_YEAR);
+ }
+
+ public static SortedMap<Date, List<Event>> byWeek(List<Event> events,
Timespan timespan)
+ {
+ return _doSort(events, timespan, Calendar.WEEK_OF_YEAR);
+ }
+
+ public static SortedMap<Date, List<Event>> byMonth(List<Event>
events, Timespan timespan)
+ {
+ return _doSort(events, timespan, Calendar.MONTH);
+ }
+
}
Modified:
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/metric/Timespan.java
===================================================================
---
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/metric/Timespan.java 2010-03-30
08:48:19 UTC (rev 1021)
+++
activity-monitor/trunk/model/src/main/java/org/jboss/bpm/monitor/model/metric/Timespan.java 2010-03-30
14:41:06 UTC (rev 1022)
@@ -73,7 +73,7 @@
Calendar cal = Calendar.getInstance();
long t1 = cal.getTimeInMillis();
- cal.roll(Calendar.DAY_OF_YEAR, -1);
+ cal.add(Calendar.DAY_OF_YEAR, -1);
long t0 = cal.getTimeInMillis();
return new Timespan(t0, t1, UNIT.HOUR, LAST_24_HOURS);
@@ -83,7 +83,7 @@
{
Calendar cal = Calendar.getInstance();
- cal.roll(Calendar.DAY_OF_YEAR, -1);
+ cal.add(Calendar.DAY_OF_YEAR, -1);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
@@ -102,7 +102,7 @@
Calendar cal = Calendar.getInstance();
long t1 = cal.getTimeInMillis();
- cal.roll(Calendar.DAY_OF_YEAR, -7);
+ cal.add(Calendar.DAY_OF_YEAR, -7);
long t0 = cal.getTimeInMillis();
return new Timespan(t0, t1, UNIT.DAY, LAST_7_DAYS);
@@ -112,7 +112,7 @@
{
Calendar cal = Calendar.getInstance();
- cal.roll(Calendar.WEEK_OF_YEAR, -1);
+ cal.add(Calendar.WEEK_OF_YEAR, -1);
cal.set(Calendar.DAY_OF_WEEK, 7);
cal.set(Calendar.HOUR_OF_DAY, 23);
@@ -134,7 +134,7 @@
Calendar cal = Calendar.getInstance();
long t1 = cal.getTimeInMillis();
- cal.roll(Calendar.WEEK_OF_YEAR, -4);
+ cal.add(Calendar.WEEK_OF_YEAR, -4);
long t0 = cal.getTimeInMillis();
return new Timespan(t0, t1, UNIT.DAY, LAST_4_WEEKS);
@@ -144,7 +144,7 @@
{
Calendar cal = Calendar.getInstance();
- cal.roll(Calendar.MONTH, -1);
+ cal.add(Calendar.MONTH, -1);
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
cal.set(Calendar.HOUR_OF_DAY, 23);
@@ -167,7 +167,7 @@
Calendar cal = Calendar.getInstance();
long t1 = cal.getTimeInMillis();
- cal.roll(Calendar.MONTH, -3);
+ cal.add(Calendar.MONTH, -3);
long t0 = cal.getTimeInMillis();
return new Timespan(t0, t1, UNIT.WEEK, LAST_3_MONTH);
@@ -194,7 +194,7 @@
cal.set(Calendar.SECOND, 59);
long t1 = cal.getTimeInMillis();
- cal.roll(Calendar.MONTH, -2);
+ cal.add(Calendar.MONTH, -2);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
@@ -210,7 +210,7 @@
Calendar cal = Calendar.getInstance();
long t1 = cal.getTimeInMillis();
- cal.roll(Calendar.YEAR, -1);
+ cal.add(Calendar.YEAR, -1);
long t0 = cal.getTimeInMillis();
return new Timespan(t0, t1, UNIT.MONTH, LAST_12_MONTH);
@@ -220,7 +220,7 @@
{
Calendar cal = Calendar.getInstance();
- cal.roll(Calendar.YEAR, -1);
+ cal.add(Calendar.YEAR, -1);
cal.set(Calendar.MONTH, Calendar.DECEMBER);
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));