LayoutXmlProcessor.java revision 0c2ed0cbaee2f206e926bfc780b05e9f1e52b551
18e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount/* 28e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * Copyright (C) 2015 The Android Open Source Project 38e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * Licensed under the Apache License, Version 2.0 (the "License"); 48e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * you may not use this file except in compliance with the License. 58e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * You may obtain a copy of the License at 68e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * http://www.apache.org/licenses/LICENSE-2.0 78e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * Unless required by applicable law or agreed to in writing, software 88e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * distributed under the License is distributed on an "AS IS" BASIS, 98e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 108e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * See the License for the specific language governing permissions and 118e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * limitations under the License. 128e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount */ 138e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 14fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool; 158e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 1697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport org.apache.commons.lang3.StringEscapeUtils; 178e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport org.xml.sax.SAXException; 188e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 19fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.BindingBuildInfo; 20fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.LayoutFileParser; 21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.store.ResourceBundle; 22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.writer.JavaFileWriter; 23a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 248e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.File; 258e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.FilenameFilter; 268e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.IOException; 278e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.io.StringWriter; 28a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyarimport java.util.ArrayList; 298e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.util.List; 308e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport java.util.UUID; 318e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 328e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.JAXBContext; 338e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.JAXBException; 348e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.bind.Marshaller; 358e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.parsers.ParserConfigurationException; 368e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountimport javax.xml.xpath.XPathExpressionException; 378e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 388e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount/** 398e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * Processes the layout XML, stripping the binding attributes and elements 408e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * and writes the information into an annotated class file for the annotation 418e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount * processor to work with. 428e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount */ 438e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mountpublic class LayoutXmlProcessor { 44a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar // hardcoded in baseAdapters 45fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount public static final String RESOURCE_BUNDLE_PACKAGE = "android.databinding.layouts"; 46a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public static final String CLASS_NAME = "DataBindingInfo"; 478e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount private final JavaFileWriter mFileWriter; 488e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount private final ResourceBundle mResourceBundle; 4997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar private final int mMinSdk; 5097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 518e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount private boolean mProcessingComplete; 528e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount private boolean mWritten; 53a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar private final boolean mIsLibrary; 548e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount private final String mBuildId = UUID.randomUUID().toString(); 55a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar // can be a list of xml files or folders that contain XML files 56a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar private final List<File> mResources; 578e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 58a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public LayoutXmlProcessor(String applicationPackage, List<File> resources, 59a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar JavaFileWriter fileWriter, int minSdk, boolean isLibrary) { 608e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount mFileWriter = fileWriter; 618e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount mResourceBundle = new ResourceBundle(applicationPackage); 62a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar mResources = resources; 6397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar mMinSdk = minSdk; 64a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar mIsLibrary = isLibrary; 65a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 66a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 67a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public static List<File> getLayoutFiles(List<File> resources) { 68a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar List<File> result = new ArrayList<File>(); 690c2ed0cbaee2f206e926bfc780b05e9f1e52b551Yigit Boyar for (File resource : resources) { 700c2ed0cbaee2f206e926bfc780b05e9f1e52b551Yigit Boyar if (!resource.exists() || !resource.canRead()) { 710c2ed0cbaee2f206e926bfc780b05e9f1e52b551Yigit Boyar continue; 720c2ed0cbaee2f206e926bfc780b05e9f1e52b551Yigit Boyar } 73a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar if (resource.isDirectory()) { 74a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar for (File layoutFolder : resource.listFiles(layoutFolderFilter)) { 75a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar for (File xmlFile : layoutFolder.listFiles(xmlFileFilter)) { 76a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar result.add(xmlFile); 77a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 78a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 79a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 80a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } else if (xmlFileFilter.accept(resource.getParentFile(), resource.getName())) { 81a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar result.add(resource); 82a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 83a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 84a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar return result; 85a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 86a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 87a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar /** 88a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * used by the studio plugin 89a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar */ 90a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public ResourceBundle getResourceBundle() { 91a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar return mResourceBundle; 928e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 938e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 944d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount public boolean processResources(int minSdk) 958e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount throws ParserConfigurationException, SAXException, XPathExpressionException, 968e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount IOException { 978e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount if (mProcessingComplete) { 988e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount return false; 998e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1008e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount LayoutFileParser layoutFileParser = new LayoutFileParser(); 101a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar for (File xmlFile : getLayoutFiles(mResources)) { 102a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar final ResourceBundle.LayoutFileBundle bindingLayout = layoutFileParser 1034d4979490e1fa374c0d7f3599fed0a9e83a579d0George Mount .parseXml(xmlFile, mResourceBundle.getAppPackage(), minSdk); 104a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar if (bindingLayout != null && !bindingLayout.isEmpty()) { 1050390898cf7c4fcad255e8cfd6802f722b516cb2cGeorge Mount mResourceBundle.addLayoutBundle(bindingLayout); 1068e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1078e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1088e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount mProcessingComplete = true; 1098e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount return true; 1108e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1118e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 112be83770af82294c1841eef414513653646b88dc6Yigit Boyar public void writeLayoutInfoFiles(File xmlOutDir) throws JAXBException { 1138e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount if (mWritten) { 1148e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount return; 1158e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1168e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount JAXBContext context = JAXBContext.newInstance(ResourceBundle.LayoutFileBundle.class); 1178e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount Marshaller marshaller = context.createMarshaller(); 118be83770af82294c1841eef414513653646b88dc6Yigit Boyar 1198e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount for (List<ResourceBundle.LayoutFileBundle> layouts : mResourceBundle.getLayoutBundles() 1208e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount .values()) { 1218e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount for (ResourceBundle.LayoutFileBundle layout : layouts) { 122a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar writeXmlFile(xmlOutDir, layout, marshaller); 1238e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1248e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1258e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount mWritten = true; 1268e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1278e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 128a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar private void writeXmlFile(File xmlOutDir, ResourceBundle.LayoutFileBundle layout, 129a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar Marshaller marshaller) throws JAXBException { 130a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar String filename = generateExportFileName(layout) + ".xml"; 131a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar String xml = toXML(layout, marshaller); 132a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar mFileWriter.writeToFile(new File(xmlOutDir, filename), xml); 133a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 134a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 135a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar public String getInfoClassFullName() { 136a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar return RESOURCE_BUNDLE_PACKAGE + "." + CLASS_NAME; 137a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 138a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 139a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar private String toXML(ResourceBundle.LayoutFileBundle layout, Marshaller marshaller) 1408e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount throws JAXBException { 141a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar StringWriter writer = new StringWriter(); 142a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar marshaller.marshal(layout, writer); 143a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar return writer.getBuffer().toString(); 144a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar } 145a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar 146a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar /** 147a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * Generates a string identifier that can uniquely identify the given layout bundle. 148a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar * This identifier can be used when we need to export data about this layout bundle. 149a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar */ 15030cc484507f3dfd7a3c56e5f785c4783e3e0da9dGeorge Mount public String generateExportFileName(ResourceBundle.LayoutFileBundle layout) { 151a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar StringBuilder name = new StringBuilder(layout.getFileName()); 152a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar name.append('-').append(layout.getDirectory()); 153a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar for (int i = name.length() - 1; i >= 0; i--) { 154a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar char c = name.charAt(i); 1558e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount if (c == '-') { 156a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar name.deleteCharAt(i); 157a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar c = Character.toUpperCase(name.charAt(i)); 158a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar name.setCharAt(i, c); 1598e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1608e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 161a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar return name.toString(); 1628e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1638e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 164b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar public void writeInfoClass(/*Nullable*/ File sdkDir, File xmlOutDir, 165b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar /*Nullable*/ File exportClassListTo) { 166b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar writeInfoClass(sdkDir, xmlOutDir, exportClassListTo, false); 167b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar } 168b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar 169b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar public void writeInfoClass(/*Nullable*/ File sdkDir, File xmlOutDir, File exportClassListTo, 170b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar boolean enableDebugLogs) { 171ee7586713d68806b556a425cbebf007a56261ff3Yigit Boyar final String sdkPath = sdkDir == null ? null : StringEscapeUtils.escapeJava(sdkDir.getAbsolutePath()); 172a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar final Class annotation = BindingBuildInfo.class; 173a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar final String layoutInfoPath = StringEscapeUtils.escapeJava(xmlOutDir.getAbsolutePath()); 174b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar final String exportClassListToPath = exportClassListTo == null ? "" : 175b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar StringEscapeUtils.escapeJava(exportClassListTo.getAbsolutePath()); 176a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar String classString = "package " + RESOURCE_BUNDLE_PACKAGE + ";\n\n" + 177a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar "import " + annotation.getCanonicalName() + ";\n\n" + 178a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar "@" + annotation.getSimpleName() + "(buildId=\"" + mBuildId + "\", " + 179a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar "modulePackage=\"" + mResourceBundle.getAppPackage() + "\", " + 180ae161289a90f6ac69ffe6411ac8c09653c81d04dYigit Boyar "sdkRoot=" + "\"" + (sdkPath == null ? "" : sdkPath) + "\"," + 181a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar "layoutInfoDir=\"" + layoutInfoPath + "\"," + 182b6887f1479c3ecec38a7989748ef33de1fbcd973Yigit Boyar "exportClassListTo=\"" + exportClassListToPath + "\"," + 183a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar "isLibrary=" + mIsLibrary + "," + 184b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar "minSdk=" + mMinSdk + "," + 185b1356339eaa6c8e967e4fc1dc283b82909a1208dYigit Boyar "enableDebugLogs=" + enableDebugLogs + ")\n" + 186a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar "public class " + CLASS_NAME + " {}\n"; 187fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount mFileWriter.writeToFile(RESOURCE_BUNDLE_PACKAGE + "." + CLASS_NAME, classString); 1888e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1898e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 190a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar private static final FilenameFilter layoutFolderFilter = new FilenameFilter() { 1918e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount @Override 1928e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount public boolean accept(File dir, String name) { 1938e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount return name.startsWith("layout"); 1948e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 1958e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount }; 1968e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount 197a6e4583962e19e8e93b4ca3f9fe3d34560b6d96cYigit Boyar private static final FilenameFilter xmlFileFilter = new FilenameFilter() { 1988e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount @Override 1998e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount public boolean accept(File dir, String name) { 2008e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount return name.toLowerCase().endsWith(".xml"); 2018e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount } 2028e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount }; 2038e5d3b4aa4e47fc0150b4a26b58ec6e5c17b9d16George Mount} 204