/* * This file is part of gwap, an open platform for games with a purpose * * Copyright (C) 2013 * Project play4science * Lehr- und Forschungseinheit für Programmier- und Modellierungssprachen * Ludwig-Maximilians-Universität München * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package gwap.admin; import gwap.model.Person; import gwap.model.Source; import gwap.model.resource.ArtResource; import gwap.model.resource.ArtResourceTitle; import gwap.wrapper.ImportedArtResource; import java.io.ByteArrayInputStream; import java.io.File; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.Query; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Logger; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.faces.FacesMessages; import org.jboss.seam.international.LocaleSelector; import org.jboss.seam.log.Log; import au.com.bytecode.opencsv.CSVReader; /** * @author Fabian Kneißl */ @Name("adminArtResourceImporter") @Scope(ScopeType.PAGE) public class ArtResourceImporter { private static final String FILENAME_REGEXP = "[A-Za-z0-9_.,()-]+"; @In private EntityManager entityManager; @Logger private Log log; @In private FacesMessages facesMessages; @In private LocaleSelector localeSelector; @In(create=true) private ArtResourceEnabled adminArtResourceEnabled; private byte[] data; private String name; private long size; private String contentType; private List<ImportedArtResource> resources; private Long sourceId; public void upload() { if (data == null) { return; } log.info("Uploaded term csv file #0 of size #1", name, size); Reader inFile = new InputStreamReader(new ByteArrayInputStream(data)); Source source = entityManager.find(Source.class, sourceId); try { parse(inFile, source); facesMessages.add("Prepared #0 resources, please review them for correctness and submit if correct.", resources.size()); log.info("#0 resources parsed", resources.size()); } catch (Exception e) { resources = null; log.error("Error parsing csv file #0", e, name); facesMessages.add("Error parsing csv file: #0", e); } } public void parse(Reader inFile, Source source) throws Exception { CSVReader csvReader = new CSVReader(inFile, ',', '"', 1); // reader, separator, delimiter, skip #rows String[] line; resources = new ArrayList<ImportedArtResource>(); HashSet<String> allFilenames = new HashSet<String>(); try { int filesNotReadable = 0; while ((line = csvReader.readNext()) != null) { // filename, image id, title, artistForename, artistSurname, year created, location, institution, origin, easement // 0 1 2 3 4 5 6 7 8 9 if (line.length != 10) throw new ImportException("Malformed row, wrong number of columns: '"+line+"'"); ImportedArtResource r = new ImportedArtResource(); r.setPath(getContentOf(line, 0)); r.setExternalId(getContentOf(line, 1)); r.setTitle(getContentOf(line, 2)); // Intelligently find forename and surname //Pattern p = Pattern.compile("(?:(.*) )?((?:\\p{Lower}+ )?(?:\\p{Alpha}+')?\\p{Upper}[\\p{Alpha}-]+)"); r.setArtistForename(getContentOf(line, 3)); r.setArtistSurname(getContentOf(line, 4)); r.setDateCreated(getContentOf(line, 5)); r.setLocation(getContentOf(line, 6)); r.setInstitution(getContentOf(line, 7)); r.setOrigin(getContentOf(line, 8)); String easementAsString = getContentOf(line, 9); if (easementAsString != null) { if ("true".equalsIgnoreCase(easementAsString)) r.setEasement(true); else if ("false".equalsIgnoreCase(easementAsString)) r.setEasement(false); else throw new ImportException("Easement should be either 'true' or 'false' and not '"+easementAsString+"'"); } // Check for illegal characters in filename if (!r.getPath().matches(FILENAME_REGEXP)) throw new ImportException("Filename must not contain characters other than "+FILENAME_REGEXP+": "+r.getPath()); // Check for correct year // if (r.getDateCreated() != null && !r.getDateCreated().matches(".*[1-9][0-9]*.*")) // throw new ImportException("Year created does not represent a year: "+r.getDateCreated()); // Check for duplicate filenames if (allFilenames.contains(r.getPath())) throw new ImportException("Duplicate entry for filename '"+r.getPath()+"'."); allFilenames.add(r.getPath()); // Check if image file exists String filePath = source.getUrl() + r.getPath(); if (!new File(filePath).canRead()) { log.error("Image with filename '"+filePath+"' does not exist or cannot be read."); filesNotReadable++; } else { resources.add(r); } } if (filesNotReadable > 0) { facesMessages.add("Could not access #0 files. Please check if all files are on the correct path and have the correct permissions.", filesNotReadable); log.error("Total number of not-accessible files: #0", filesNotReadable); } } finally { csvReader.close(); } } private String getContentOf(String[] line, int i) { String content = line[i]; if (content == null) return null; content = content.trim(); if (content.isEmpty()) return null; return content; } public void doImport() { Source source = entityManager.find(Source.class, sourceId); for (ImportedArtResource r : resources) { ArtResource artResource = r.toArtResource(); entityManager.persist(artResource); ArtResourceTitle arTitle = new ArtResourceTitle(); arTitle.setTitle(r.getTitle()); arTitle.setResource(artResource); entityManager.persist(arTitle); artResource.setSource(source); Person artist = findOrCreateArtist(r.getArtistForename(), r.getArtistSurname()); artResource.setArtist(artist); adminArtResourceEnabled.updateArtResource(artResource); } facesMessages.add("Successfully imported #0 images.", resources.size()); resources = null; } private Person findOrCreateArtist(String forename, String surname) { Query q = entityManager.createNamedQuery("person.byForenameAndSurname"); q.setParameter("forename", forename); q.setParameter("surname", surname); Person person; try { person = (Person) q.getSingleResult(); } catch (NoResultException e) { person = new Person(); person.setUsername(""); person.setForename(forename); person.setSurname(surname); entityManager.persist(person); } return person; } public byte[] getData() { return data; } public void setData(byte[] data) { this.data = data; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSize() { return size; } public void setSize(long size) { this.size = size; } public String getContentType() { return contentType; } public void setContentType(String contentType) { this.contentType = contentType; } public Long getSourceId() { return sourceId; } public void setSourceId(Long sourceId) { this.sourceId = sourceId; } public List<ImportedArtResource> getResources() { return resources; } public void setResources(List<ImportedArtResource> resources) { this.resources = resources; } }