Java tutorial
/* * Copyright 2016 Shunyi Chen * * 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.dockingsoftware.dockingpreference; import com.dockingsoftware.dockingpreference.persistent.DefaultPersistentAdapter; import com.dockingsoftware.dockingpreference.persistent.PersistentAdapterIF; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; public class PreferenceProcessor { /** * Loads preference by filePath. * * @param filePath * @return */ public Object load(String filePath) { Object obj = null; File file = new File(filePath); if (!file.exists()) { return null; } try { SAXReader reader = new SAXReader(); Document doc = reader.read(file); Element parent = doc.getRootElement(); NodeInfo rootInfo = new NodeInfo(parent); obj = Class.forName(rootInfo.getClazz()).newInstance(); load(obj, parent); } catch (DocumentException ex) { String errMsg = "The system cannot find the file specified path " + filePath + "."; Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, errMsg, ex); } catch (ClassNotFoundException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } catch (IllegalArgumentException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } catch (InstantiationException ex) { String errMsg = "No-args constructor is missing for " + ex.getMessage(); Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, errMsg, ex); } catch (IllegalAccessException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } catch (Exception ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } return obj; } /** * Loads user preference information. * * @param obj the object whose field should be modified */ public void load(Object obj) { String filePath = GlobalConstant.USER_HOME + "/" + obj.getClass().getName() + GlobalConstant.FILE_EXTENSION; File file = new File(filePath); if (!file.exists()) { return; } try { SAXReader reader = new SAXReader(); Document doc = reader.read(file); Element parent = doc.getRootElement(); load(obj, parent); } catch (DocumentException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } catch (ClassNotFoundException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } catch (IllegalArgumentException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } catch (InstantiationException ex) { String errMsg = "No-args constructor is missing for " + ex.getMessage(); Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, errMsg, ex); } catch (IllegalAccessException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } catch (Exception ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } } /** * Loads user preference information. * * @param obj * @param parent * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalArgumentException * @throws IllegalAccessException */ private void load(Object obj, Element parent) throws ClassNotFoundException, InstantiationException, IllegalArgumentException, IllegalAccessException, Exception { Class cls = obj.getClass(); if (cls.isArray()) { List<NodeInfo> infos = new ArrayList<NodeInfo>(); List<Element> lstChildren = parent.elements(); for (int i = 0; i < lstChildren.size(); i++) { Element child = lstChildren.get(i); NodeInfo nodeInfo = new NodeInfo(child); infos.add(nodeInfo); } Object array = obj; for (int i = 0; i < infos.size(); i++) { NodeInfo info = infos.get(i); Class fieldClass = Class.forName(info.getClazz()); if (!StringUtils.isBlank(info.getValue())) { PersistentAdapterIF adapter; if (info.getAdapter() == null) { adapter = new DefaultPersistentAdapter(); } else { adapter = (PersistentAdapterIF) Class.forName(info.getAdapter()).newInstance(); } //Gets the new value for the field of obj. Object fieldValue = adapter.restore(info.getValue(), fieldClass); Array.set(array, i, fieldValue); } else { Object fieldValue = fieldClass.newInstance(); // Loading children load(fieldValue, info.getElement()); Array.set(array, i, fieldValue); } } } else if (obj instanceof Collection) { List<NodeInfo> infos = new ArrayList<NodeInfo>(); List<Element> lstChildren = parent.elements(); for (int i = 0; i < lstChildren.size(); i++) { Element child = lstChildren.get(i); NodeInfo nodeInfo = new NodeInfo(child); infos.add(nodeInfo); } Collection coll = (Collection) obj; for (int i = 0; i < infos.size(); i++) { NodeInfo info = infos.get(i); Class fieldClass = Class.forName(info.getClazz()); if (!StringUtils.isBlank(info.getValue())) { PersistentAdapterIF adapter = null; if (info.getAdapter() == null) { adapter = new DefaultPersistentAdapter(); } else { adapter = (PersistentAdapterIF) Class.forName(info.getAdapter()).newInstance(); } //Gets the new value for the field of obj. Object fieldValue = adapter.restore(info.getValue(), fieldClass); coll.add(fieldValue); } else { Object fieldValue = fieldClass.newInstance(); // Loading children load(fieldValue, info.getElement()); coll.add(fieldValue); } } } else if (obj instanceof Map) { // Key is always String type. Map<String, NodeInfo> infos = new HashMap<String, NodeInfo>(); List<Element> lstKeys = parent.elements(); for (int i = 0; i < lstKeys.size(); i++) { Element keyEle = lstKeys.get(i); Element valueEle = (Element) keyEle.elements().get(0); NodeInfo valueInfo = new NodeInfo(valueEle); infos.put(keyEle.getText().trim(), valueInfo); } Map map = (Map) obj; Iterator<String> iter = infos.keySet().iterator(); while (iter.hasNext()) { String key = iter.next(); NodeInfo valueInfo = infos.get(key); Class fieldClass = Class.forName(valueInfo.getClazz()); if (!StringUtils.isBlank(valueInfo.getValue())) { PersistentAdapterIF adapter = null; if (valueInfo.getAdapter() == null) { adapter = new DefaultPersistentAdapter(); } else { adapter = (PersistentAdapterIF) Class.forName(valueInfo.getAdapter()).newInstance(); } //Gets the new value for the field of obj. Object fieldValue = adapter.restore(valueInfo.getValue(), fieldClass); map.put(key, fieldValue); } else { Object fieldValue = fieldClass.newInstance(); // Loading children load(fieldValue, valueInfo.getElement()); map.put(key, fieldValue); } } } else { Map<String, NodeInfo> infos = new HashMap<String, NodeInfo>(); List<Element> lstChildren = parent.elements(); for (int i = 0; i < lstChildren.size(); i++) { Element child = lstChildren.get(i); NodeInfo nodeInfo = new NodeInfo(child); infos.put(nodeInfo.getName(), nodeInfo); } Field[] fields = cls.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fields[i].setAccessible(true); NodeInfo info = infos.get(fields[i].getName()); if (info != null) { Class fieldClass = Class.forName(info.getClazz()); if (!StringUtils.isBlank(info.getValue())) { PersistentAdapterIF adapter = null; if (info.getAdapter() == null) { adapter = new DefaultPersistentAdapter(); } else { adapter = (PersistentAdapterIF) Class.forName(info.getAdapter()).newInstance(); } //Gets the new value for the field of obj. Object fieldValue = adapter.restore(info.getValue(), fieldClass); fields[i].set(obj, fieldValue); } else { if (fieldClass == java.lang.reflect.Array.class) { Class arryCls = Class.forName(info.getArrayType()); Object fieldValue = Array.newInstance(arryCls, Integer.parseInt(info.getArrayLength())); // Loading children load(fieldValue, info.getElement()); fields[i].set(obj, fieldValue); } else { Object fieldValue = fieldClass.newInstance(); // Loading children load(fieldValue, info.getElement()); fields[i].set(obj, fieldValue); } } } } } } /** * Store user preference information to default file. * * @param obj */ public void store(Object obj) { store(obj, GlobalConstant.USER_HOME + "/" + obj.getClass().getName() + GlobalConstant.FILE_EXTENSION); } /** * Store user preference information to a specified file. * * @param obj * @param fullPath Specified the full path of the configuration file. */ public void store(Object obj, String fullPath) { try { FileWriter out; Document document = DocumentHelper.createDocument(); Element root = document.addElement(getName(obj.getClass())); root.addAttribute(GlobalConstant.CLASS, obj.getClass().getName()); List<Field> pFields = getPreferenceFieldList(obj.getClass()); for (int i = 0; i < pFields.size(); i++) { store(obj, pFields.get(i), root); } OutputFormat format = new OutputFormat(" ", true); out = new FileWriter(new File(fullPath)); XMLWriter w = new XMLWriter(out, format); w.write(document); w.close(); out.close(); } catch (IOException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } catch (IllegalArgumentException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } } /** * Store object tree into XML file. * * @param obj * @param alias * @param parent * @throws IllegalArgumentException * @throws IllegalAccessException */ private void store(Object obj, Field field, Element parent) throws IllegalArgumentException, IllegalAccessException { Object fieldValue = field.get(obj); PreferenceField pf = field.getAnnotation(com.dockingsoftware.dockingpreference.PreferenceField.class); if (fieldValue != null) { store(field.getType(), field.getName(), fieldValue, parent, pf.adapter()); } } /** * Store object tree into XML file. * * @param fieldClass * @param fieldName * @param fieldValue * @param parent * @param adapterClass * @throws IllegalArgumentException * @throws IllegalAccessException */ private void store(Class fieldClass, String fieldName, Object fieldValue, Element parent, Class<? extends PersistentAdapterIF> adapterClass) throws IllegalArgumentException, IllegalAccessException { if (fieldClass.isArray()) { if (fieldName.endsWith("[]")) { fieldName = fieldName.substring(0, fieldName.length() - 2); } Object[] array = (Object[]) fieldValue; Element arrayEle = parent.addElement(fieldName); String arryType = fieldClass.getName(); arryType = arryType.substring(arryType.lastIndexOf("[") + 2, arryType.length() - 1); arrayEle.addAttribute(GlobalConstant.CLASS, GlobalConstant.ARRAY); arrayEle.addAttribute(GlobalConstant.ARRAY_TYPE, arryType); arrayEle.addAttribute(GlobalConstant.ARRAY_LENGTH, array.length + ""); for (int i = 0; i < array.length; i++) { List<Field> arrFields = getPreferenceFieldList(array[i].getClass()); if (arrFields.size() > 0) { Element child = arrayEle.addElement(getName(array[i].getClass())); child.addAttribute(GlobalConstant.CLASS, array[i].getClass().getName()); for (int j = 0; j < arrFields.size(); j++) { store(array[i], arrFields.get(j), child); } } else { store(array[i].getClass(), array[i].getClass().getSimpleName(), array[i], arrayEle, adapterClass); } } } else if (fieldValue instanceof Collection) { Element lstEle = parent.addElement(fieldName); lstEle.addAttribute(GlobalConstant.CLASS, fieldValue.getClass().getName()); Collection coll = (Collection) fieldValue; Iterator iter = coll.iterator(); while (iter.hasNext()) { Object item = iter.next(); List<Field> lstFields = getPreferenceFieldList(item.getClass()); if (lstFields.size() > 0) { Element child = lstEle.addElement(getName(item.getClass())); child.addAttribute(GlobalConstant.CLASS, item.getClass().getName()); for (int j = 0; j < lstFields.size(); j++) { store(item, lstFields.get(j), child); } } else { store(item.getClass(), item.getClass().getSimpleName(), item, lstEle, adapterClass); } } } else if (fieldValue instanceof Map) { Element mapEle = parent.addElement(fieldName); mapEle.addAttribute(GlobalConstant.CLASS, fieldValue.getClass().getName()); Map map = (Map) fieldValue; Iterator iter = map.keySet().iterator(); while (iter.hasNext()) { Object key = iter.next(); Object value = map.get(key); Element keyEle = mapEle.addElement(GlobalConstant.KEY); keyEle.setText(key.toString());// Not suppert any adapter! keyEle.addAttribute(GlobalConstant.CLASS, key.getClass().getName()); List<Field> vFields = getPreferenceFieldList(value.getClass()); if (vFields.size() > 0) { Element valueEle = keyEle.addElement(getName(value.getClass())); valueEle.addAttribute(GlobalConstant.CLASS, value.getClass().getName()); for (int j = 0; j < vFields.size(); j++) { store(value, vFields.get(j), valueEle); } } else { store(value.getClass(), value.getClass().getSimpleName(), value, keyEle, adapterClass); } } } else { List<Field> pFields = getPreferenceFieldList(fieldValue.getClass()); if (pFields.size() > 0) { Element child = parent.addElement(fieldName); child.addAttribute(GlobalConstant.CLASS, fieldValue.getClass().getName()); for (int i = 0; i < pFields.size(); i++) { store(fieldValue, pFields.get(i), child); } } else { Element attrEle = parent.addElement(fieldName); attrEle.setText(getValue(fieldValue, adapterClass)); attrEle.addAttribute(GlobalConstant.CLASS, fieldValue.getClass().getName()); if (adapterClass != DefaultPersistentAdapter.class) { attrEle.addAttribute(GlobalConstant.ADAPTER, adapterClass.getName()); } } } } /** * Gets the listing of preference field. * * @param c * @return */ private List<Field> getPreferenceFieldList(Class c) { List<Field> lstFields = new ArrayList<Field>(); Field[] fields = c.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fields[i].setAccessible(true); PreferenceField pf = fields[i] .getAnnotation(com.dockingsoftware.dockingpreference.PreferenceField.class); if (pf != null) { lstFields.add(fields[i]); } } return lstFields; } /** * Gets the simple name of the class. * * @param c * @return */ private String getName(Class c) { return c.getSimpleName(); } /** * Gets the value that's processed by adapter. * * @param obj * @param adapterClass * @return */ private String getValue(Object obj, Class<? extends PersistentAdapterIF> adapterClass) { try { return ((PersistentAdapterIF) adapterClass.newInstance()).store(obj); } catch (InstantiationException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, "No-args constructor is missing.", ex); } catch (IllegalAccessException ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } catch (Exception ex) { Logger.getLogger(PreferenceProcessor.class.getName()).log(Level.SEVERE, null, ex); } return null; } }