java/alt2xml-in-fs/src/cz/frantovo/alt2xml/in/fs/Reader.java
author František Kučera <franta-hg@frantovo.cz>
Sun, 02 Oct 2016 15:23:20 +0200
changeset 109 76df01fc4aa2
parent 106 02739f60b1ec
child 111 e4900596abdb
permissions -rw-r--r--
in-fs: comment, symlinks
     1 /**
     2  * Alt2XML
     3  * Copyright © 2014 František Kučera (frantovo.cz)
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, either version 3 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License
    16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
    17  */
    18 package cz.frantovo.alt2xml.in.fs;
    19 
    20 import cz.frantovo.alt2xml.AbstractAlt2XmlReader;
    21 import java.io.File;
    22 import java.io.IOException;
    23 import java.net.URI;
    24 import java.net.URISyntaxException;
    25 import java.nio.ByteBuffer;
    26 import java.nio.file.Files;
    27 import java.nio.file.LinkOption;
    28 import java.nio.file.Path;
    29 import java.nio.file.attribute.PosixFilePermission;
    30 import java.nio.file.attribute.UserDefinedFileAttributeView;
    31 import java.nio.file.spi.FileSystemProvider;
    32 import java.util.List;
    33 import java.util.ArrayList;
    34 import java.util.Set;
    35 import java.util.logging.Logger;
    36 import org.xml.sax.Attributes;
    37 import org.xml.sax.InputSource;
    38 import org.xml.sax.SAXException;
    39 import org.xml.sax.helpers.AttributesImpl;
    40 
    41 /**
    42  * Reads filesystem – hierarchical structure of directories and files.
    43  *
    44  * @author Ing. František Kučera (frantovo.cz)
    45  */
    46 public class Reader extends AbstractAlt2XmlReader {
    47 
    48 	public static final String ROOT_ELEMENT = "fs";
    49 	public static final String DIR_ELEMENT = "dir";
    50 	public static final String FILE_ELEMENT = "file";
    51 	public static final String XATTR_ELEMENT = "xattr";
    52 	public static final String PERMISSIONS_ELEMENT = "mode";
    53 	public static final String PERMISSIONS_U_ELEMENT = "user";
    54 	public static final String PERMISSIONS_G_ELEMENT = "group";
    55 	public static final String PERMISSIONS_O_ELEMENT = "others";
    56 	public static final String NAME_ATTRIBUTE = "name";
    57 	public static final String ABSOLUTE_PATH_ATTRIBUTE = "path";
    58 	public static final String SIZE_ATTRIBUTE = "size";
    59 	private static final Logger log = Logger.getLogger(Reader.class.getName());
    60 
    61 	/**
    62 	 * indentation level
    63 	 */
    64 	private int level = 0;
    65 
    66 	@Override
    67 	public void parse(InputSource input) throws IOException, SAXException {
    68 		File dir = getFile(input.getSystemId());
    69 
    70 		outputStart(dir);
    71 		outputDir(dir);
    72 		outputEnd();
    73 	}
    74 
    75 	private File getFile(String systemId) throws IOException {
    76 		try {
    77 			return new File(new URI(systemId));
    78 		} catch (URISyntaxException e) {
    79 			throw new IOException("Invalid dir URI", e);
    80 		}
    81 	}
    82 
    83 	private String getAbsolutePath(File file) throws IOException {
    84 		return file.getCanonicalFile().getAbsolutePath();
    85 	}
    86 
    87 	private Attributes singleAttribute(String name, int value) {
    88 		AttributesImpl attributes = new AttributesImpl();
    89 		addAttribute(attributes, name, value);
    90 		return attributes;
    91 	}
    92 
    93 	private Attributes singleAttribute(String name, String value) {
    94 		AttributesImpl attributes = new AttributesImpl();
    95 		addAttribute(attributes, name, value);
    96 		return attributes;
    97 	}
    98 
    99 	private void addAttribute(AttributesImpl attributes, String name, int value) {
   100 		attributes.addAttribute(null, name, name, "xs:int", String.valueOf(value));
   101 	}
   102 
   103 	private void addAttribute(AttributesImpl attributes, String name, long value) {
   104 		attributes.addAttribute(null, name, name, "xs:long", String.valueOf(value));
   105 	}
   106 
   107 	private void addAttribute(AttributesImpl attributes, String name, String value) {
   108 		attributes.addAttribute(null, name, name, "xs:string", value);
   109 	}
   110 
   111 	private void outputStart(File root) throws SAXException, IOException {
   112 		contentHandler.startDocument();
   113 		contentHandler.lineBreak();
   114 		contentHandler.startElement(null, null, ROOT_ELEMENT, singleAttribute(ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(root)));
   115 		contentHandler.lineBreak();
   116 	}
   117 
   118 	private void outputEnd() throws SAXException {
   119 		contentHandler.endElement(null, null, ROOT_ELEMENT);
   120 		contentHandler.lineBreak();
   121 		contentHandler.endDocument();
   122 	}
   123 
   124 	private void outputFile(File file) throws SAXException, IOException {
   125 		level++;
   126 
   127 		AttributesImpl attributes = new AttributesImpl();
   128 		addAttribute(attributes, NAME_ATTRIBUTE, file.getName());
   129 		addAttribute(attributes, ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(file));
   130 		addAttribute(attributes, SIZE_ATTRIBUTE, file.length());
   131 
   132 		contentHandler.indentation(level);
   133 		contentHandler.startElement(null, null, FILE_ELEMENT, attributes);
   134 		contentHandler.lineBreak();
   135 
   136 		outputPermissions(file.toPath());
   137 		outputExtendedAttributes(file);
   138 
   139 		contentHandler.indentation(level);
   140 		contentHandler.endElement(null, null, FILE_ELEMENT);
   141 		contentHandler.lineBreak();
   142 
   143 		level--;
   144 	}
   145 
   146 	private void outputDir(File dir) throws SAXException, IOException {
   147 		level++;
   148 
   149 		final File[] children = dir.listFiles();
   150 
   151 		AttributesImpl attributes = new AttributesImpl();
   152 		addAttribute(attributes, NAME_ATTRIBUTE, dir.getName());
   153 		addAttribute(attributes, ABSOLUTE_PATH_ATTRIBUTE, getAbsolutePath(dir));
   154 		addAttribute(attributes, SIZE_ATTRIBUTE, children.length);
   155 
   156 		contentHandler.indentation(level);
   157 		contentHandler.startElement(null, null, DIR_ELEMENT, attributes);
   158 		contentHandler.lineBreak();
   159 
   160 		outputPermissions(dir.toPath());
   161 		outputExtendedAttributes(dir);
   162 
   163 		for (File file : children) {
   164 			if (file.isDirectory()) {
   165 				outputDir(file);
   166 			} else {
   167 				outputFile(file);
   168 			}
   169 		}
   170 
   171 		contentHandler.indentation(level);
   172 		contentHandler.endElement(null, null, DIR_ELEMENT);
   173 		contentHandler.lineBreak();
   174 
   175 		level--;
   176 	}
   177 
   178 	private String encodeElementName(String originalName) {
   179 		/**
   180 		 * TODO: encode and/or skip invalid characters
   181 		 */
   182 		return originalName;
   183 	}
   184 
   185 	private void outputPermissions(Path path) throws IOException, SAXException {
   186 		level++;
   187 		Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(path); // TODO: maybe symlinks: LinkOption.NOFOLLOW_LINKS
   188 
   189 		contentHandler.indentation(level);
   190 		contentHandler.startElement(null, PERMISSIONS_ELEMENT, PERMISSIONS_ELEMENT, singleAttribute("octal", getOctal(permissions)));
   191 		contentHandler.lineBreak();
   192 
   193 		level++;
   194 
   195 		outputPermission("owner", permissions.contains(PosixFilePermission.OWNER_READ), permissions.contains(PosixFilePermission.OWNER_WRITE), permissions.contains(PosixFilePermission.OWNER_EXECUTE));
   196 		outputPermission("group", permissions.contains(PosixFilePermission.GROUP_READ), permissions.contains(PosixFilePermission.GROUP_WRITE), permissions.contains(PosixFilePermission.GROUP_EXECUTE));
   197 		outputPermission("others", permissions.contains(PosixFilePermission.OTHERS_READ), permissions.contains(PosixFilePermission.OTHERS_WRITE), permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
   198 
   199 		level--;
   200 
   201 		contentHandler.indentation(level);
   202 		contentHandler.endElement(null, PERMISSIONS_ELEMENT, PERMISSIONS_ELEMENT);
   203 		contentHandler.lineBreak();
   204 
   205 		level--;
   206 	}
   207 
   208 	private int getOctal(Set<PosixFilePermission> permissions) {
   209 		int octal = 0;
   210 
   211 		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_READ) ? 4 : 0);
   212 		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_WRITE) ? 2 : 0);
   213 		octal = octal + 100 * (permissions.contains(PosixFilePermission.OWNER_EXECUTE) ? 1 : 0);
   214 
   215 		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_READ) ? 4 : 0);
   216 		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_WRITE) ? 2 : 0);
   217 		octal = octal + 10 * (permissions.contains(PosixFilePermission.GROUP_EXECUTE) ? 1 : 0);
   218 
   219 		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_READ) ? 4 : 0);
   220 		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_WRITE) ? 2 : 0);
   221 		octal = octal + 1 * (permissions.contains(PosixFilePermission.OTHERS_EXECUTE) ? 1 : 0);
   222 
   223 		return octal;
   224 	}
   225 
   226 	private void outputPermission(String name, boolean read, boolean write, boolean execute) throws SAXException {
   227 		contentHandler.indentation(level);
   228 		AttributesImpl attributes = new AttributesImpl();
   229 		attributes.addAttribute(null, "read", "read", "xs:boolean", String.valueOf(read));
   230 		attributes.addAttribute(null, "write", "write", "xs:boolean", String.valueOf(write));
   231 		attributes.addAttribute(null, "execute", "execute", "xs:boolean", String.valueOf(execute));
   232 		contentHandler.startElement(null, name, name, attributes);
   233 		contentHandler.endElement(null, name, name);
   234 		contentHandler.lineBreak();
   235 	}
   236 
   237 	private void outputExtendedAttributes(File file) throws IOException, SAXException {
   238 		level++;
   239 
   240 		final List<ExtendedAttribute> extendedAttributes = getExtendedAttributes(file);
   241 
   242 		if (!extendedAttributes.isEmpty()) {
   243 			contentHandler.indentation(level);
   244 			contentHandler.startElement(null, XATTR_ELEMENT, XATTR_ELEMENT, null);
   245 			contentHandler.lineBreak();
   246 			level++;
   247 			for (ExtendedAttribute ea : extendedAttributes) {
   248 				contentHandler.indentation(level);
   249 				String elementName = encodeElementName(ea.getKey());
   250 				contentHandler.textElement(ea.getValue(), null, elementName, elementName, null);
   251 				contentHandler.lineBreak();
   252 			}
   253 			level--;
   254 			contentHandler.indentation(level);
   255 			contentHandler.endElement(null, XATTR_ELEMENT, XATTR_ELEMENT);
   256 			contentHandler.lineBreak();
   257 		}
   258 
   259 		level--;
   260 	}
   261 
   262 	private List<ExtendedAttribute> getExtendedAttributes(File file) throws IOException {
   263 
   264 		List<ExtendedAttribute> l = new ArrayList<>();
   265 
   266 		Path path = file.toPath();
   267 		FileSystemProvider provider = path.getFileSystem().provider();
   268 		UserDefinedFileAttributeView attributes = provider.getFileAttributeView(path, UserDefinedFileAttributeView.class);
   269 
   270 		for (String jménoAtributu : attributes.list()) {
   271 			ByteBuffer hodnotaAtributu = ByteBuffer.allocate(attributes.size(jménoAtributu));
   272 			attributes.read(jménoAtributu, hodnotaAtributu);
   273 			l.add(new ExtendedAttribute(jménoAtributu, hodnotaAtributu));
   274 		}
   275 
   276 		return l;
   277 
   278 	}
   279 }