001 /*
002 *
003 * $Revision: 14986 $ $Date: 2009-03-20 21:41:45 +0100 (Fri, 20 Mar 2009) $
004 *
005 * This file is part of *** M y C o R e ***
006 * See http://www.mycore.de/ for details.
007 *
008 * This program is free software; you can use it, redistribute it
009 * and / or modify it under the terms of the GNU General Public License
010 * (GPL) as published by the Free Software Foundation; either version 2
011 * of the License or (at your option) any later version.
012 *
013 * This program is distributed in the hope that it will be useful, but
014 * WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program, in a file called gpl.txt or license.txt.
020 * If not, write to the Free Software Foundation Inc.,
021 * 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA
022 */
023
024 package org.mycore.frontend.fileupload;
025
026 import java.io.InputStream;
027 import java.util.Collection;
028 import java.util.StringTokenizer;
029
030 import org.apache.log4j.Logger;
031 import org.hibernate.Transaction;
032 import org.mycore.access.MCRAccessInterface;
033 import org.mycore.access.MCRAccessManager;
034 import org.mycore.backend.hibernate.MCRHIBConnection;
035 import org.mycore.common.MCRConfiguration;
036 import org.mycore.common.MCRException;
037 import org.mycore.datamodel.ifs.MCRDirectory;
038 import org.mycore.datamodel.ifs.MCRFile;
039 import org.mycore.datamodel.ifs.MCRFilesystemNode;
040 import org.mycore.datamodel.metadata.MCRDerivate;
041 import org.mycore.datamodel.metadata.MCRMetaIFS;
042 import org.mycore.datamodel.metadata.MCRMetaLinkID;
043 import org.mycore.datamodel.metadata.MCRObjectID;
044
045 /**
046 * handles uploads via the UploadApplet and store files directly into the IFS.
047 *
048 * @author Thomas Scheffler (yagee)
049 *
050 * @version $Revision: 14986 $ $Date: 2009-03-20 21:41:45 +0100 (Fri, 20 Mar 2009) $
051 *
052 * @see MCRUploadHandler
053 */
054 public class MCRUploadHandlerIFS extends MCRUploadHandler {
055
056 protected MCRDerivate derivate;
057
058 protected MCRDirectory rootDir;
059
060 protected boolean newDerivate = true;
061
062 private Transaction tx;
063
064 private static final String ID_TYPE = "derivate";
065
066 private static final String PROJECT = MCRConfiguration.instance().getString("MCR.SWF.Project.ID", "MCR");
067
068 private static final Logger LOGGER = Logger.getLogger(MCRUploadHandlerIFS.class);
069
070 private static final MCRConfiguration CONFIG = MCRConfiguration.instance();
071
072 public MCRUploadHandlerIFS(String docId, String derId, String url) {
073 super();
074 this.url = url;
075 init(docId, derId);
076 }
077
078 protected void init(String docId, String derId) {
079 if (derId == null) {
080 // create new derivate
081 LOGGER.debug("derId=null create derivate with next free ID");
082 createNewDerivate(docId, getFreeDerivateID());
083 } else {
084 if (MCRDerivate.existInDatastore(derId)) {
085 LOGGER.debug("Derivate allready exists: " + derId);
086 newDerivate = false;
087 derivate = new MCRDerivate();
088 derivate.receiveFromDatastore(derId);
089 } else {
090 // create new derivate with given ID
091 LOGGER.debug("derId='" + derId + "' create derivate with that ID");
092 createNewDerivate(docId, new MCRObjectID(derId));
093 }
094 }
095 }
096
097 /**
098 * Start Upload for MyCoRe
099 */
100 public void startUpload(int numFiles) throws Exception {
101 if (newDerivate) {
102 LOGGER.debug("Create new derivate with id: " + derivate.getId());
103 derivate.createInDatastore();
104 }
105 rootDir = getRootDir(derivate.getId().toString());
106 }
107
108 /**
109 * Message from UploadApplet If you want all files transfered omit this
110 * method
111 *
112 * @param path
113 * file name
114 * @param checksum
115 * md5 checksum of of file
116 * @param length
117 * the length of the file in bytes (file size)
118 *
119 * @return true transfer file false don't send file
120 *
121 */
122 public boolean acceptFile(String path, String checksum, long length) throws Exception {
123 MCRFilesystemNode child = rootDir.getChildByPath(path);
124 if (!(child instanceof MCRFile)) {
125 return true;
126 }
127 MCRFile file = (MCRFile) child;
128 return !checksum.equals(file.getMD5());
129 }
130
131 public synchronized long receiveFile(String path, InputStream in, long length, String md5) throws Exception {
132 try {
133 LOGGER.debug("adding file: " + path);
134 startTransaction();
135 MCRFile file = getNewFile(path);
136 commitTransaction();
137 long sizeDiff = file.setContentFrom(in, false);
138 startTransaction();
139 file.storeContentChange(sizeDiff);
140 commitTransaction();
141
142 long myLength = file.getSize();
143 if (myLength >= length)
144 return myLength;
145 else {
146 file.delete(); // Incomplete file transfer, user canceled upload
147 return 0;
148 }
149 } catch (Exception e) {
150 LOGGER.error("Error while uploading file: "+path,e);
151 try {
152 rollbackTransaction();
153 } catch (Exception e2) {
154 LOGGER.debug("Error while rolling back transaction",e);
155 }
156 return 0;
157 }
158 }
159
160 /**
161 * Finish upload, store derivate
162 *
163 */
164 public void finishUpload() throws Exception {
165 String mainfile = getMainFilePath(rootDir);
166 if (newDerivate) {
167 derivate.getDerivate().getInternals().setMainDoc(mainfile);
168 derivate.updateXMLInDatastore();
169 setDefaultPermissions(derivate.getId());
170 } else {
171 String mf = derivate.getDerivate().getInternals().getMainDoc();
172 if (mf.trim().length() == 0) {
173 derivate.getDerivate().getInternals().setMainDoc(mainfile);
174 derivate.updateXMLInDatastore();
175 }
176 }
177 }
178
179 private static MCRObjectID getFreeDerivateID() {
180 MCRObjectID derivateID = new MCRObjectID();
181 derivateID.setNextFreeId(PROJECT + '_' + ID_TYPE);
182 return derivateID;
183 }
184
185 protected void createNewDerivate(String docId, MCRObjectID newDerID) {
186 newDerivate = true;
187 derivate = new MCRDerivate();
188 derivate.setId(newDerID);
189 String schema = CONFIG.getString("MCR.Metadata.Config.derivate", "datamodel-derivate.xml").replaceAll(".xml", ".xsd");
190 derivate.setSchema(schema);
191 derivate.setLabel("data object from " + docId);
192 // set link to Object
193 MCRMetaLinkID linkId = new MCRMetaLinkID();
194 linkId.setSubTag("linkmeta");
195 linkId.setReference(docId, null, null);
196 MCRMetaIFS ifs = new MCRMetaIFS();
197 ifs.setSubTag("internal");
198 ifs.setSourcePath(null);
199 derivate.getDerivate().setInternals(ifs);
200 derivate.getDerivate().setLinkMeta(linkId);
201 }
202
203 private MCRFile getNewFile(String path) {
204 if (path.indexOf("/") == -1) {
205 return new MCRFile(path, rootDir);
206 }
207 StringTokenizer tok = new StringTokenizer(path, "/");
208 MCRDirectory parent = rootDir;
209 while (tok.hasMoreTokens()) {
210 String child = tok.nextToken();
211 if (parent.hasChild(child)) {
212 MCRFilesystemNode childNode = parent.getChild(child);
213 if ((childNode instanceof MCRFile) && !tok.hasMoreTokens()) {
214 return (MCRFile) childNode;
215 } else if (childNode instanceof MCRDirectory) {
216 parent = (MCRDirectory) childNode;
217 } else {
218 // obviously a file should not contain any other files
219 return null;
220 }
221 } else {
222 if (tok.hasMoreTokens()) {
223 parent = new MCRDirectory(child, parent);
224 } else {
225 // NOTE: How should we handle empty directories?
226 return new MCRFile(child, parent);
227 }
228 }
229 }
230 LOGGER.error("Please investigate getNewFile() method in IFS upload handler. Server shouldn't get to this point!");
231 return null;
232 }
233
234 private static MCRDirectory getRootDir(String derID) {
235 MCRFilesystemNode root = MCRFilesystemNode.getRootNode(derID);
236 if (!(root instanceof MCRDirectory)) {
237 root = new MCRDirectory(derID, derID);
238 }
239 MCRDirectory rootDir = (MCRDirectory) root;
240 return rootDir;
241 }
242
243 protected static String getMainFilePath(MCRDirectory root) {
244 MCRDirectory parent = root;
245 while (parent.hasChildren()) {
246 MCRFilesystemNode[] children = parent.getChildren(MCRDirectory.SORT_BY_NAME);
247 if (children[0] instanceof MCRDirectory) {
248 parent = (MCRDirectory) children[0];
249 }
250 for (int i = 0; i < children.length; i++) {
251 if (children[i] instanceof MCRFile)
252 return children[i].getAbsolutePath().substring(1);
253 }
254 }
255 return "";
256 }
257
258 protected static void setDefaultPermissions(MCRObjectID derID) {
259 if (CONFIG.getBoolean("MCR.Access.AddDerivateDefaultRule", true)) {
260 MCRAccessInterface AI = MCRAccessManager.getAccessImpl();
261 Collection<String> configuredPermissions = AI.getAccessPermissionsFromConfiguration();
262 for (String permission : configuredPermissions) {
263 MCRAccessManager.addRule(derID, permission, MCRAccessManager.getTrueRule(), "default derivate rule");
264 }
265 }
266 }
267
268 protected void startTransaction() {
269 LOGGER.debug("Starting transaction");
270 if (tx == null || !tx.isActive())
271 tx = MCRHIBConnection.instance().getSession().beginTransaction();
272 else
273 throw new MCRException("Transaction already started");
274 }
275
276 protected void commitTransaction() {
277 LOGGER.debug("Committing transaction");
278 if (tx != null) {
279 tx.commit();
280 tx = null;
281 } else
282 throw new NullPointerException("Cannot commit transaction");
283 }
284
285 protected void rollbackTransaction() {
286 LOGGER.debug("Rolling back transaction");
287 if (tx != null) {
288 tx.rollback();
289 tx = null;
290 } else
291 throw new NullPointerException("Cannot rollback transaction");
292 }
293
294 }