View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe 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   * MyCoRe 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 MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.datamodel.ifs2;
20  
21  import java.io.IOException;
22  import java.nio.file.Files;
23  import java.nio.file.Path;
24  import java.nio.file.StandardCopyOption;
25  import java.nio.file.attribute.BasicFileAttributes;
26  
27  import org.apache.commons.io.IOUtils;
28  import org.apache.logging.log4j.LogManager;
29  import org.apache.logging.log4j.Logger;
30  import org.jdom2.Element;
31  import org.mycore.common.content.MCRContent;
32  import org.mycore.common.content.streams.MCRDevNull;
33  import org.mycore.datamodel.ifs.MCRContentInputStream;
34  import org.mycore.datamodel.niofs.MCRFileAttributes;
35  
36  /**
37   * Represents a file stored in a file collection. This is a file that is
38   * imported from outside the system, and may be updated and modified afterwards.
39   * 
40   * @author Frank Lützenkirchen
41   * 
42   */
43  public class MCRFile extends MCRStoredNode {
44  
45      private static final MCRDevNull DEV_NULL = new MCRDevNull();
46  
47      private static final Logger LOGGER = LogManager.getLogger(MCRFile.class);
48  
49      /**
50       * The md5 checksum of the empty file
51       */
52      public static final String MD5_OF_EMPTY_FILE = "d41d8cd98f00b204e9800998ecf8427e";
53  
54      /**
55       * Returns a MCRFile object representing an existing file already stored in
56       * the store.
57       * 
58       * @param parent
59       *            the parent directory containing this file
60       * @param fo
61       *            the file in the local underlying filesystem storing this file
62       */
63      protected MCRFile(MCRDirectory parent, Path fo, Element data) {
64          super(parent, fo, data);
65      }
66  
67      /**
68       * Creates a new MCRFile that does not exist yet
69       * 
70       * @param parent
71       *            the parent directory
72       * @param name
73       *            the file name
74       */
75      protected MCRFile(MCRDirectory parent, String name) throws IOException {
76          super(parent, name, "file");
77          Files.createFile(path);
78          writeData(e -> e.setAttribute("md5", MCRFile.MD5_OF_EMPTY_FILE));
79          getRoot().saveAdditionalData();
80      }
81  
82      /**
83       * Returns a MCRVirtualNode contained in this file as a child. A file that
84       * is a container, like zip or tar, may contain other files as children.
85       */
86      @Override
87      protected MCRVirtualNode buildChildNode(Path fo) {
88          return null; //not implemented
89      }
90  
91      /**
92       * Returns the md5 checksum of the file's content.
93       * 
94       * @return the md5 checksum of the file's content.
95       */
96      public String getMD5() {
97          return readData(e -> e.getAttributeValue("md5"));
98      }
99  
100     /**
101      * Returns the file name extension, which is the part after the last dot in
102      * the filename.
103      * 
104      * @return the file extension, or the empty string if the file name does not
105      *         have an extension
106      */
107     public String getExtension() {
108         String name = getName();
109         int pos = name.lastIndexOf(".");
110         return pos == -1 ? "" : name.substring(pos + 1);
111     }
112 
113     /**
114      * Sets the content of this file.
115      * 
116      * @param source
117      *            the content to be read
118      * @return the MD5 checksum of the stored content
119      */
120     public String setContent(MCRContent source) throws IOException {
121         try (MCRContentInputStream cis = source.getContentInputStream()) {
122             source.sendTo(path, StandardCopyOption.REPLACE_EXISTING);
123             String md5 = cis.getMD5String();
124             writeData(e -> e.setAttribute("md5", md5));
125             getRoot().saveAdditionalData();
126             return md5;
127         }
128     }
129 
130     /**
131      * updates the MD5 sum of this file to the given value.
132      *
133      * Use only if you modified the content outside of {@link #setContent(MCRContent)}.
134      * @param md5
135      * @throws IOException
136      */
137     public void setMD5(String md5) throws IOException {
138         writeData(e -> e.setAttribute("md5", md5));
139         getRoot().saveAdditionalData();
140     }
141 
142     /**
143      * Repairs additional metadata of this file and all its children
144      */
145     @Override
146     void repairMetadata() throws IOException {
147         MCRContentInputStream cis = getContent().getContentInputStream();
148         IOUtils.copy(cis, DEV_NULL);
149         cis.close();
150         String path = getPath();
151         writeData(e -> {
152             e.setName("file");
153             e.setAttribute("name", getName());
154             e.removeChildren("file");
155             e.removeChildren("directory");
156             String md5 = cis.getMD5String();
157             if (!md5.equals(e.getAttributeValue("md5"))) {
158                 LOGGER.warn("Fixed MD5 of {} to {}", path, md5);
159                 e.setAttribute("md5", md5);
160             }
161         });
162     }
163 
164     @Override
165     public MCRFileAttributes<String> getBasicFileAttributes() throws IOException {
166         BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
167         return MCRFileAttributes.fromAttributes(attrs, getMD5());
168     }
169 }