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    }