content: /*
   * Copyright 1999-2012 Alibaba Group.
   *  
   * 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 com.alibaba.cobar.manager.dao.xml;
  
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.util.Collections;
  import java.util.concurrent.locks.ReentrantLock;
  
  import org.apache.log4j.Logger;
  import org.springframework.beans.factory.InitializingBean;
  import org.xmlpull.mxp1.MXParser;
  import org.xmlpull.mxp1_serializer.MXSerializer;
  import org.xmlpull.v1.XmlPullParser;
  import org.xmlpull.v1.XmlPullParserException;
  
  import com.alibaba.cobar.manager.dao.PropertyDAO;
  import com.alibaba.cobar.manager.dataobject.xml.PropertyDO;
  
  /**
   * @author haiqing.zhuhq 2011-6-17
   */
  public class PropertyDAOImple extends AbstractDAOImple implements PropertyDAO, InitializingBean {
      private static final Logger logger = Logger.getLogger(PropertyDAOImple.class);
      private static final ReentrantLock lock = new ReentrantLock();
      private PropertyDO property;
  
      public PropertyDAOImple() {
          this.xpp = new MXParser();
          this.xsl = new MXSerializer();
          this.property = new PropertyDO();
      }
  
      public PropertyDO getProperty() {
          return property;
      }
  
      public void setProperty(PropertyDO property) {
          this.property = property;
      }
  
      private boolean read() {
          FileInputStream is = null;
          lock.lock();
          try {
              property.getStopTimes().clear();
              is = new FileInputStream(xmlPath);
              xpp.setInput(is, "UTF-8");
              while (!(xpp.getEventType() == XmlPullParser.END_TAG && "pro".equals(xpp.getName()))) {
                  if (xpp.getEventType() == XmlPullParser.START_TAG && "property".equals(xpp.getName())) {
                      if ("stop_times".equals(xpp.getAttributeValue(0))) {
                          String value = xpp.nextText().trim();
                          String[] times = value.split(",");
                          for (int i = 0; i < times.length; i++) {
                              property.getStopTimes().add(Integer.parseInt(times[i].trim()));
                          }
                          Collections.sort(property.getStopTimes());
                      }
                  }
                  xpp.next();
              }
              is.close();
              return true;
          } catch (FileNotFoundException e) {
              logger.error(e.getMessage(), e);
          } catch (XmlPullParserException e) {
              logger.error(e.getMessage(), e);
          } catch (IOException e) {
              logger.error(e.getMessage(), e);
          } finally {
              lock.unlock();
          }
          if (null != is) {
              try {
                  is.close();
              } catch (IOException e) {
                  logger.error(e.getMessage(), e);
              }
          }
          return false;
      }
  
      private boolean write() {
          FileOutputStream os = null;
          lock.lock();
          try {
              if (!backup(xmlPath)) {
                  logger.error("property backup fail!");
              }
              os = new FileOutputStream(xmlPath);
              xsl.setOutput(os, "UTF-8");
              xsl.startDocument("UTF-8", null);
              xsl.text("\n");
              xsl.startTag(null, "pro");
              xsl.text("\n");
              String st = property.toString();
              writeProperty("stop_times", st);
              xsl.endTag(null, "pro");
              xsl.endDocument();
              os.close();
              return true;
          } catch (FileNotFoundException e) {
              logger.error(e.getMessage(), e);
          } catch (IOException e) {
              logger.error(e.getMessage(), e);
          } finally {
              lock.unlock();
          }
          if (null != os) {
              try {
                  os.close();
              } catch (IOException e) {
                  logger.error(e.getMessage(), e);
              }
          }
          return false;
      }
  
      @Override
      public void afterPropertiesSet() throws Exception {
          xmlPath = xmlFileLoader.getFilePath();
          if (null == xmlPath) {
              logger.error("property xmlpath doesn't set!");
              throw new IllegalArgumentException("property xmlpath doesn't set!");
          } else {
              if (xmlPath.endsWith(System.getProperty("file.separator"))) {
                  xmlPath = new StringBuilder(xmlPath).append("property.xml").toString();
              } else {
                  xmlPath =
                          new StringBuilder(xmlPath).append(System.getProperty("file.separator"))
                                                    .append("property.xml")
                                                    .toString();
              }
              read();
          }
      }
  
      @Override
      public boolean addTime(int time) {
          lock.lock();
          try {
              if (property.getStopTimes().contains(time)) {
                  return false;
              }
              property.getStopTimes().add(time);
              Collections.sort(property.getStopTimes());
              if (!write()) {
                  logger.error("Fail to add property!");
                  recovery(xmlPath);
                  read();
                  return false;
              }
          } finally {
              lock.unlock();
          }
          return true;
      }
  
      @Override
      public boolean deleteTime(int time) {
          if (!property.getStopTimes().contains(time)) {
              logger.warn("Time (" + time + ") to delete does not exist!");
              return false;
          }
          property.getStopTimes().remove((Integer) time);
          if (!write()) {
              logger.error("Fail to delete property!");
              recovery(xmlPath);
              read();
              return false;
          }
          return true;
      }
  
  }
  