1 package charactermanaj.model.io;
\r
3 import java.io.ByteArrayOutputStream;
\r
5 import java.io.FileOutputStream;
\r
6 import java.io.IOException;
\r
7 import java.io.OutputStream;
\r
8 import java.io.OutputStreamWriter;
\r
10 import java.nio.charset.Charset;
\r
11 import java.text.SimpleDateFormat;
\r
12 import java.util.ArrayList;
\r
13 import java.util.Collection;
\r
14 import java.util.Collections;
\r
15 import java.util.HashMap;
\r
16 import java.util.List;
\r
17 import java.util.Locale;
\r
19 import javax.xml.XMLConstants;
\r
20 import javax.xml.parsers.DocumentBuilder;
\r
21 import javax.xml.parsers.DocumentBuilderFactory;
\r
22 import javax.xml.parsers.ParserConfigurationException;
\r
23 import javax.xml.transform.OutputKeys;
\r
24 import javax.xml.transform.Transformer;
\r
25 import javax.xml.transform.TransformerConfigurationException;
\r
26 import javax.xml.transform.TransformerException;
\r
27 import javax.xml.transform.TransformerFactory;
\r
28 import javax.xml.transform.dom.DOMSource;
\r
29 import javax.xml.transform.stream.StreamResult;
\r
31 import org.w3c.dom.Attr;
\r
32 import org.w3c.dom.Document;
\r
33 import org.w3c.dom.Element;
\r
35 import charactermanaj.model.PartsAuthorInfo;
\r
36 import charactermanaj.model.PartsManageData;
\r
37 import charactermanaj.model.PartsManageData.PartsKey;
\r
39 public class PartsInfoXMLWriter {
\r
44 public static final String NS_PARTSDEF = "http://charactermanaj.sourceforge.jp/schema/charactermanaj-partsdef";
\r
47 * パーツ管理情報をDocBaseと同じフォルダ上のparts-info.xmlに書き出す.<br>
\r
48 * XML生成中に失敗した場合は既存の管理情報は残される.<br>
\r
49 * (管理情報の書き込み中にI/O例外が発生した場合は管理情報は破壊される.)<br>
\r
53 * @param partsManageData
\r
55 * @throws IOException
\r
58 public void savePartsManageData(URI docBase, PartsManageData partsManageData)
\r
59 throws IOException {
\r
60 if (docBase == null || partsManageData == null) {
\r
61 throw new IllegalArgumentException();
\r
64 if (!"file".equals(docBase.getScheme())) {
\r
65 throw new IOException("ファイル以外はサポートしていません: " + docBase);
\r
67 File docBaseFile = new File(docBase);
\r
68 File baseDir = docBaseFile.getParentFile();
\r
70 // データからXMLを構築してストリームに出力する.
\r
71 // 完全に成功したXMLのみ書き込むようにするため、一旦バッファする。
\r
72 ByteArrayOutputStream bos = new ByteArrayOutputStream();
\r
74 savePartsManageData(partsManageData, bos);
\r
79 // バッファされたXMLデータを実際のファイルに書き込む
\r
80 File partsInfoXML = new File(baseDir, "parts-info.xml");
\r
81 FileOutputStream os = new FileOutputStream(partsInfoXML);
\r
83 os.write(bos.toByteArray());
\r
90 * パーツ管理情報をXMLとしてストリームに書き出す.<br>
\r
92 * @param partsManageData
\r
96 * @throws IOException
\r
99 public void savePartsManageData(PartsManageData partsManageData,
\r
100 OutputStream outstm) throws IOException {
\r
101 if (partsManageData == null || outstm == null) {
\r
102 throw new IllegalArgumentException();
\r
107 DocumentBuilderFactory factory = DocumentBuilderFactory
\r
109 factory.setNamespaceAware(true);
\r
110 DocumentBuilder builder = factory.newDocumentBuilder();
\r
111 doc = builder.newDocument();
\r
113 } catch (ParserConfigurationException ex) {
\r
114 throw new RuntimeException("JAXP Configuration Exception.", ex);
\r
117 Locale locale = Locale.getDefault();
\r
118 String lang = locale.getLanguage();
\r
120 Element root = doc.createElementNS(NS_PARTSDEF, "parts-definition");
\r
122 root.setAttribute("xmlns:xml", XMLConstants.XML_NS_URI);
\r
123 root.setAttribute("xmlns:xsi",
\r
124 "http://www.w3.org/2001/XMLSchema-instance");
\r
125 root.setAttribute("xsi:schemaLocation", NS_PARTSDEF
\r
126 + " parts-definition.xsd");
\r
127 doc.appendChild(root);
\r
130 Collection<PartsAuthorInfo> partsAuthors = partsManageData
\r
132 for (PartsAuthorInfo partsAuthorInfo : partsAuthors) {
\r
133 String author = partsAuthorInfo.getAuthor();
\r
134 if (author == null || author.length() == 0) {
\r
139 Element nodeAuthor = doc.createElementNS(NS_PARTSDEF, "author");
\r
140 Element nodeAuthorName = doc.createElementNS(NS_PARTSDEF, "name");
\r
141 Attr attrLang = doc.createAttributeNS(XMLConstants.XML_NS_URI,
\r
143 attrLang.setValue(lang);
\r
144 nodeAuthorName.setAttributeNodeNS(attrLang);
\r
145 nodeAuthorName.setTextContent(author);
\r
146 nodeAuthor.appendChild(nodeAuthorName);
\r
148 String homepageURL = partsAuthorInfo.getHomePage();
\r
149 if (homepageURL != null && homepageURL.length() > 0) {
\r
150 Element nodeHomepage = doc.createElementNS(NS_PARTSDEF,
\r
152 Attr attrHomepageLang = doc.createAttributeNS(
\r
153 XMLConstants.XML_NS_URI, "lang");
\r
154 attrHomepageLang.setValue(lang);
\r
155 nodeHomepage.setAttributeNodeNS(attrHomepageLang);
\r
156 nodeHomepage.setTextContent(homepageURL);
\r
157 nodeAuthor.appendChild(nodeHomepage);
\r
160 root.appendChild(nodeAuthor);
\r
162 Collection<PartsKey> partsKeys = partsManageData
\r
163 .getPartsKeysByAuthor(author);
\r
165 // ダウンロード別にパーツキーの集約
\r
166 HashMap<String, List<PartsKey>> downloadMap = new HashMap<String, List<PartsKey>>();
\r
167 for (PartsKey partsKey : partsKeys) {
\r
168 PartsManageData.PartsVersionInfo versionInfo = partsManageData
\r
169 .getVersionStrict(partsKey);
\r
170 String downloadURL = versionInfo.getDownloadURL();
\r
171 if (downloadURL == null) {
\r
174 List<PartsKey> partsKeyGrp = downloadMap.get(downloadURL);
\r
175 if (partsKeyGrp == null) {
\r
176 partsKeyGrp = new ArrayList<PartsKey>();
\r
177 downloadMap.put(downloadURL, partsKeyGrp);
\r
179 partsKeyGrp.add(partsKey);
\r
182 // ダウンロード別にパーツ情報の登録
\r
183 ArrayList<String> downloadURLs = new ArrayList<String>(
\r
184 downloadMap.keySet());
\r
185 Collections.sort(downloadURLs);
\r
188 final SimpleDateFormat dateTimeFmt = new SimpleDateFormat(
\r
189 "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
\r
191 for (String downloadURL : downloadURLs) {
\r
192 List<PartsKey> partsKeyGrp = downloadMap.get(downloadURL);
\r
193 Collections.sort(partsKeyGrp);
\r
195 Element nodeDownload = doc.createElementNS(NS_PARTSDEF,
\r
197 nodeDownload.setTextContent(downloadURL);
\r
198 root.appendChild(nodeDownload);
\r
200 for (PartsKey partsKey : partsKeyGrp) {
\r
201 PartsManageData.PartsVersionInfo versionInfo = partsManageData
\r
202 .getVersionStrict(partsKey);
\r
204 Element nodeParts = doc.createElementNS(NS_PARTSDEF,
\r
207 nodeParts.setAttribute("name", partsKey.getPartsName());
\r
208 if (partsKey.getCategoryId() != null) {
\r
209 nodeParts.setAttribute("category",
\r
210 partsKey.getCategoryId());
\r
212 if (versionInfo.getVersion() > 0) {
\r
213 nodeParts.setAttribute("version",
\r
214 Double.toString(versionInfo.getVersion()));
\r
217 if (versionInfo.getLastModified() != null) {
\r
218 nodeParts.setAttribute("lastModified", dateTimeFmt
\r
219 .format(versionInfo.getLastModified()));
\r
222 String localizedName = partsManageData
\r
223 .getLocalizedName(partsKey);
\r
224 if (localizedName != null
\r
225 && localizedName.trim().length() > 0) {
\r
226 Element nodeLocalizedName = doc.createElementNS(
\r
227 NS_PARTSDEF, "local-name");
\r
228 Attr attrLocalizedNameLang = doc.createAttributeNS(
\r
229 XMLConstants.XML_NS_URI, "lang");
\r
230 attrLocalizedNameLang.setValue(lang);
\r
232 .setAttributeNodeNS(attrLocalizedNameLang);
\r
233 nodeLocalizedName.setTextContent(localizedName);
\r
234 nodeParts.appendChild(nodeLocalizedName);
\r
237 root.appendChild(nodeParts);
\r
243 TransformerFactory txFactory = TransformerFactory.newInstance();
\r
244 txFactory.setAttribute("indent-number", Integer.valueOf(4));
\r
247 tfmr = txFactory.newTransformer();
\r
248 } catch (TransformerConfigurationException ex) {
\r
249 throw new RuntimeException("JAXP Configuration Failed.", ex);
\r
251 tfmr.setOutputProperty(OutputKeys.INDENT, "yes");
\r
253 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4504745
\r
254 final String encoding = "UTF-8";
\r
255 tfmr.setOutputProperty("encoding", encoding);
\r
257 tfmr.transform(new DOMSource(doc), new StreamResult(
\r
258 new OutputStreamWriter(outstm, Charset.forName(encoding))));
\r
260 } catch (TransformerException ex) {
\r
261 IOException ex2 = new IOException("XML Convert failed.");
\r