/* * 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 static com.alibaba.cobar.manager.util.ConstantDefine.DEPLOY_CONTACT; import static com.alibaba.cobar.manager.util.ConstantDefine.DEPLOY_DESC; import static com.alibaba.cobar.manager.util.ConstantDefine.ID; import static com.alibaba.cobar.manager.util.ConstantDefine.MAINT_CONTACT; import static com.alibaba.cobar.manager.util.ConstantDefine.NAME; import static com.alibaba.cobar.manager.util.ConstantDefine.ONLINE_TIME; import static com.alibaba.cobar.manager.util.ConstantDefine.SORT_ID; import static com.alibaba.cobar.manager.util.ConstantDefine.STATUS; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; 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.ClusterDAO; import com.alibaba.cobar.manager.dataobject.xml.ClusterDO; /** * @author haiqing.zhuhq 2011-6-14 */ public class ClusterDAOImple extends AbstractDAOImple implements ClusterDAO, InitializingBean { private static final Logger logger = Logger.getLogger(ClusterDAOImple.class); private Map<Long, ClusterDO> map; private static long maxId; private static final ReentrantLock lock = new ReentrantLock(); private static final Map<String, Integer> typeMap = new HashMap<String, Integer>(); static { typeMap.put("id", ID); typeMap.put("name", NAME); typeMap.put("status", STATUS); typeMap.put("deployContact", DEPLOY_CONTACT); typeMap.put("maintContact", MAINT_CONTACT); typeMap.put("onlineTime", ONLINE_TIME); typeMap.put("deployDesc", DEPLOY_DESC); typeMap.put("sortId", SORT_ID); } public ClusterDAOImple() { map = new HashMap<Long, ClusterDO>(); xpp = new MXParser(); xsl = new MXSerializer(); maxId = Long.MIN_VALUE; } private boolean read() { FileInputStream is = null; lock.lock(); try { map.clear(); is = new FileInputStream(xmlPath); xpp.setInput(is, "UTF-8"); while (!(xpp.getEventType() == XmlPullParser.END_TAG && "clusters".equals(xpp.getName()))) { if (xpp.getEventType() == XmlPullParser.START_TAG && "cluster".equals(xpp.getName())) { ClusterDO cluster = read(xpp); if (null == cluster) { throw new XmlPullParserException("Cluster read error"); } maxId = (maxId < cluster.getId()) ? cluster.getId() : maxId; map.put(cluster.getId(), cluster); } 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 { maxId = maxId < 0 ? 0 : maxId; lock.unlock(); } if (null != is) { try { is.close(); } catch (IOException e) { logger.error(e.getMessage(), e); } } return false; } @SuppressWarnings("rawtypes") private boolean write() { FileOutputStream os = null; lock.lock(); try { if (!backup(xmlPath)) { logger.error("cluster backup fail!"); } os = new FileOutputStream(xmlPath); xsl.setOutput(os, "UTF-8"); xsl.startDocument("UTF-8", null); xsl.text("\n"); xsl.startTag(null, "clusters"); xsl.text("\n"); Iterator it = map.entrySet().iterator(); while (it.hasNext()) { @SuppressWarnings("unchecked") Map.Entry<Long, ClusterDO> entry = (Entry<Long, ClusterDO>) it.next(); ClusterDO cluster = entry.getValue(); if (!write(cluster)) { throw new IOException("cluster write error!"); } } xsl.endTag(null, "clusters"); xsl.endDocument(); os.close(); return true; } 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; } private boolean write(ClusterDO cluster) { try { writePrefix(false); xsl.startTag(null, "cluster"); xsl.text("\n"); writeProperty("id", String.valueOf(cluster.getId())); writeProperty("sortId", String.valueOf(cluster.getSortId())); writeProperty("name", cluster.getName()); writeProperty("deployContact", cluster.getDeployContact()); writeProperty("maintContact", cluster.getMaintContact()); writeProperty("onlineTime", cluster.getOnlineTime()); writeProperty("deployDesc", cluster.getDeployDesc()); writePrefix(true); xsl.endTag(null, "cluster"); xsl.text("\n"); return true; } catch (IOException e) { logger.error(e.getMessage(), e); } return false; } private ClusterDO read(XmlPullParser xpp) { ClusterDO cluster = new ClusterDO(); cluster.setSortId(0); try { while (!(xpp.getEventType() == XmlPullParser.END_TAG && "cluster".equals(xpp.getName()))) { if (xpp.getEventType() == XmlPullParser.START_TAG && "property".equals(xpp.getName())) { int type = typeMap.get(xpp.getAttributeValue(0).trim()); switch (type) { case ID: cluster.setId(Long.parseLong(xpp.nextText().trim())); break; case SORT_ID: cluster.setSortId(Integer.parseInt(xpp.nextText().trim())); break; case NAME: cluster.setName(xpp.nextText().trim()); break; case DEPLOY_CONTACT: cluster.setDeployContact(xpp.nextText().trim()); break; case MAINT_CONTACT: cluster.setMaintContact(xpp.nextText().trim()); break; case DEPLOY_DESC: cluster.setDeployDesc(xpp.nextText().trim()); break; case ONLINE_TIME: cluster.setOnlineTime(xpp.nextText().trim()); break; default: break; } } xpp.next(); } return cluster; } catch (NumberFormatException e) { logger.error(e.getMessage(), e); } catch (XmlPullParserException e) { logger.error(e.getMessage(), e); } catch (IOException e) { logger.error(e.getMessage(), e); } return null; } @Override public void afterPropertiesSet() throws Exception { xmlPath = xmlFileLoader.getFilePath(); if (null == xmlPath) { logger.error("cluster xmlpath doesn't set!"); throw new IllegalArgumentException("cluster xmlpath doesn't set!"); } else { if (xmlPath.endsWith(System.getProperty("file.separator"))) { xmlPath = new StringBuilder(xmlPath).append("cluster.xml").toString(); } else { xmlPath = new StringBuilder(xmlPath).append(System.getProperty("file.separator")) .append("cluster.xml") .toString(); } read(); } } @Override public ClusterDO getClusterById(long id) { return map.get(id); } @Override public boolean modifyCluster(ClusterDO cluster) { lock.lock(); try { if (!checkName(cluster.getName(), cluster.getId())) { return false; } map.put(cluster.getId(), cluster); if (!write()) { logger.error("Fail to modify cluster!"); recovery(xmlPath); read(); return false; } } finally { lock.unlock(); } return true; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public boolean checkName(String name) { Iterator it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Long, ClusterDO> entry = (Entry<Long, ClusterDO>) it.next(); ClusterDO cluster = entry.getValue(); if (name.equals(cluster.getName())) { return false; } } return true; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public boolean checkName(String name, long id) { Iterator it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Long, ClusterDO> entry = (Entry<Long, ClusterDO>) it.next(); ClusterDO cluster = entry.getValue(); if (cluster.getId() == id) { continue; } if (name.equals(cluster.getName())) { return false; } } return true; } @Override public boolean addCluster(ClusterDO cluster) { lock.lock(); try { if (!checkName(cluster.getName())) { return false; } cluster.setId(++maxId); map.put(cluster.getId(), cluster); if (!write()) { logger.error("Fail to add cluster!"); recovery(xmlPath); read(); return false; } } finally { lock.unlock(); } return true; } @Override public List<ClusterDO> listAllCluster() { return new ArrayList<ClusterDO>(map.values()); } }