001 /* 002 @license.text@ 003 */ 004 package biz.hammurapi.metrics.persistent; 005 006 import java.sql.SQLException; 007 import java.util.Iterator; 008 import java.util.LinkedList; 009 import java.util.List; 010 011 import org.w3c.dom.Element; 012 013 import biz.hammurapi.sql.SQLRuntimeException; 014 015 /** 016 * Measurement period for a particular metric 017 * @author Pavel Vlasov 018 * @version $Revision$ 019 */ 020 public class Period extends AbstractPeriod { 021 private int id; 022 /** 023 * Period primary key 024 */ 025 static class Key { 026 private int id; 027 private int hashCode; 028 private long timeFrom; 029 private long timeTo; 030 private int slices; 031 private boolean shrink; 032 033 /** 034 * @param id 035 * @param timeFrom 036 * @param timeTo 037 */ 038 public Key(int id, long timeFrom, long timeTo, int slices, boolean shrink) { 039 super(); 040 this.id = id; 041 this.timeFrom = timeFrom; 042 this.timeTo = timeTo; 043 hashCode=id ^ new Long(timeFrom).hashCode() ^ new Long(timeTo).hashCode() ^ slices ^ new Boolean(shrink).hashCode(); 044 } 045 046 public boolean equals(Object arg) { 047 return (arg==this || 048 (arg instanceof Key 049 && ((Key) arg).id==id 050 && ((Key) arg).timeFrom==timeFrom 051 && ((Key) arg).timeTo==timeTo 052 && ((Key) arg).slices==slices 053 && ((Key) arg).shrink==shrink)); 054 } 055 056 public int hashCode() { 057 return hashCode; 058 } 059 } 060 061 /** 062 * Actual from and to can differ from the passed if shrink is true slices don't cover all the period. 063 * @param processor 064 * @param id 065 * @param from 066 * @param to 067 * @param periods 068 * @param shrink Shrink period to exclude leading and trailing times without measurements. 069 * @throws SQLException 070 */ 071 Period(PeriodFactory factory, Key key) throws SQLException { 072 this(factory, null, key.id, key.timeFrom, key.timeTo, key.slices, key.shrink); 073 name=factory.getEngine().getMetric(id).getName(); 074 } 075 076 /** 077 * Actual from and to can differ from the passed if shrink is true slices don't cover all the period. 078 * @param processor 079 * @param id 080 * @param from 081 * @param to 082 * @param periods 083 * @param shrink Shrink period to exclude leading and trailing times without measurements. 084 * @throws SQLException 085 */ 086 Period(PeriodFactory factory, int id, long from, long to, int slices, boolean shrink) throws SQLException { 087 this(factory, null, id, from, to, slices, shrink); 088 name=factory.getEngine().getMetric(id).getName(); 089 } 090 091 /** 092 * Actual from and to can differ from the passed if shrink is true slices don't cover all the period. 093 * @param processor 094 * @param id 095 * @param from 096 * @param to 097 * @param periods 098 * @param shrink Shrink period to exclude leading and trailing times without measurements. 099 * @throws SQLException 100 */ 101 private Period(PeriodFactory factory, String name, int id, long from, long to, int slices, boolean shrink) throws SQLException { 102 this.name=name; 103 this.id=id; 104 MetricsEngine engine = factory.getEngine(); 105 this.factory=factory; 106 107 key=new Key(id, from, to, slices, shrink); 108 109 this.timeFrom=from; 110 this.timeTo=to; 111 if (shrink) { 112 ActualPeriod actualPeriod = engine.getActualPeriod(id, to, from); 113 if (actualPeriod!=null && actualPeriod.getTimeFrom()!=actualPeriod.getTimeTo()) { 114 if (actualPeriod.getTimeFrom()>from) { 115 this.timeFrom=actualPeriod.getTimeFrom()-1; 116 } 117 118 if (actualPeriod.getTimeTo()<to) { 119 this.timeTo=actualPeriod.getTimeTo()+1; 120 } 121 } 122 } 123 124 createSlices(slices); 125 126 // calculate values for slices and totals here 127 Iterator it=engine.getSlice(id, this.timeTo, this.timeFrom).iterator(); 128 while (it.hasNext()) { 129 aggregate((Slice) it.next()); 130 } 131 132 normalizeSliceDeviations(); 133 } 134 135 private Key key; 136 137 /** 138 * @return Returns the id. 139 */ 140 public int getId() { 141 return id; 142 } 143 144 public boolean equals(Object arg) { 145 return arg==this || (arg instanceof Period && key.equals(((Period) arg).toKey())); 146 } 147 148 public int hashCode() { 149 return key.hashCode; 150 } 151 152 /** 153 * Primary key of period to use in memory sensitive cache. 154 * @return 155 */ 156 public Object toKey() { 157 return key; 158 } 159 160 /** 161 * @param holder 162 */ 163 protected void setAttributes(Element holder) { 164 super.setAttributes(holder); 165 holder.setAttribute("id", String.valueOf(id)); 166 holder.setAttribute("absolute-name", getAbsoluteName()); 167 } 168 169 public void toDom(Element holder) { 170 super.toDom(holder); 171 MetricRef[] path = getPath(); 172 for (int i=0; i<path.length; i++) { 173 Element pe=holder.getOwnerDocument().createElement("path"); 174 holder.appendChild(pe); 175 pe.setAttribute("id", String.valueOf(path[i].getId())); 176 pe.setAttribute("name", path[i].getName()); 177 } 178 } 179 180 /** 181 * @throws SQLException 182 */ 183 protected void loadSubCategories(List subCategories) throws SQLException { 184 Iterator it = factory.getEngine().getActiveMetrics(getId(), getTimeTo(), getTimeFrom()).iterator(); 185 while (it.hasNext()) { 186 Period subPeriod = factory.getPeriod(((Number) it.next()).intValue(), getTimeFrom(), getTimeTo(), slices.length, false); 187 if (subPeriod.getMeasurements()!=0) { 188 subCategories.add(subPeriod); 189 } 190 } 191 } 192 193 public String getAbsoluteName() { 194 StringBuffer ret=new StringBuffer(); 195 MetricRef[] path = getPath(); 196 for (int i=0; i<path.length; i++) { 197 ret.append(path[i].getName()); 198 ret.append("."); 199 } 200 ret.append(getName()); 201 return ret.toString(); 202 } 203 204 private MetricRef[] path; 205 206 public MetricRef[] getPath() { 207 if (path==null) { 208 LinkedList pathList=new LinkedList(); 209 try { 210 for (Metric m=factory.getEngine().getMetric(getId()); m!=null; m = m.getParent()==null ? null : factory.getEngine().getMetric(m.getParent().intValue())) { 211 if (m.getId()!=getId()) { 212 pathList.addFirst(m); 213 } 214 } 215 } catch (SQLException e) { 216 throw new SQLRuntimeException(e); 217 } 218 path=(MetricRef[]) pathList.toArray(new MetricRef[pathList.size()]); 219 } 220 return path; 221 } 222 223 }