/**
* Copyright 1999-2009 The Pegadi Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pegadi.model;
// XML imports
import no.dusken.common.model.Person;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Date;
/**
* This class represents an article.
*
* @author Håvard Wigtil <havardw at pvv.org>
* @author Jørgen Binningsbø <jb@underdusken.no>
* @version $Revision: 2774 $, $Date$
*/
public class Article implements Serializable, Comparable {
/**
* The minimum amount of text an xml document can contain
*/
private static final int XML_MINIMUM = 10;
/**
* The maximum length of the article name
*/
private static final int MAX_NAME_LENGTH = 128;
/**
* The XML representation of this document.
*/
private Document mDoc;
/**
* the name of this article
*/
private String articleName;
/**
* the ID of this article
*/
private int id;
/**
* the journalist owning this article
*/
private Person journalist;
/**
* the photographer assigned to this article
*/
private Person photographer;
/**
* the description of this article
*/
private String description;
/**
* is the article-xml editable?
*/
private boolean canEditXML = false;
/**
* is this article viewable
*/
private boolean canView = true;
/**
* the publication where this article is scheduled for printing
*/
private Publication publication;
/**
* the section this article belongs to
*/
private Section section;
/**
* the type of this article
*/
private ArticleType articleType;
/**
* the status of this article
*/
private ArticleStatus articleStatus;
/**
* the current number of characters for this article. warning:
* only updated when the article is saved.
*/
private int currentNumberOfCharacters;
/**
* the wanted number of characters for this article.
*/
private int wantedNumberOfCharacters;
/**
* the wanted number of pages for this article.
*/
private float wantedNumberOfPages;
/**
* The serialized XML-text of this Article
*/
private String text;
/**
* The date the article was last saved
*/
private Date lastSaved;
/**
* Compares the article to another article by name.
* If name is equal it compares by ID
*
* @param o the object to compare to
* @return positive if name is after, negative if before
*/
public int compareTo(Object o) {
Article art = (Article) o;
int lastCmp = this.getName().compareTo(art.getName());
if (lastCmp == 0) {
lastCmp = this.getId() - art.getId();
}
return lastCmp;
}
/**
* Returns the ID of this article.
*
* @return an <code>int</code> value, or <code>null</code> if no ID is set.
*/
public int getId() {
return id;
}
/**
* Sets the ID of this article
*
* @param id the id of the article
*/
public void setId(int id) {
this.id = id;
}
/**
* Returns the name of this article
*
* @return the name of the article
*/
public String getName() {
return articleName;
}
/**
* Returns the string representation of this article
*
* @return the string representation of the article
*/
public String toString() {
return getName();
}
/**
* Sets the name of this article
*
* @param articleName the name of the article
*/
public void setName(String articleName) {
if(articleName == null || articleName.length() < MAX_NAME_LENGTH)
this.articleName = articleName;
else {
this.articleName = articleName.substring(0, MAX_NAME_LENGTH);
}
}
/**
* Returns the journalist assigned to this article
*
* @return the journalist user object
*/
public Person getJournalist() {
return journalist;
}
/**
* Sets the journalist assigned to this article
*
* @param journalist the journalist user object
*/
public void setJournalist(Person journalist) {
this.journalist = journalist;
}
/**
* Returns the photographer assigned to this article
*
* @return the photographer user object
*/
public Person getPhotographer() {
return photographer;
}
/**
* Sets the photographer assigned to this article
*
* @param photographer the photographer user object
*/
public void setPhotographer(Person photographer) {
this.photographer = photographer;
}
/**
* Gets the description of this article
*
* @return the description
*/
public String getDescription() {
return description;
}
/**
* Sets the description of this article
*
* @param description the description
*/
public void setDescription(String description) {
this.description = description;
}
/**
* Gets the publication this article is scheduled for
*
* @return the publication object
*/
public Publication getPublication() {
return publication;
}
/**
* Sets the publication for this article
*
* @param publication the publication object
*/
public void setPublication(Publication publication) {
this.publication = publication;
}
/**
* Sets the text for this article
*
* @param doc the parsed XML DOM Document object
*/
public void setDoc(Document doc) {
this.mDoc = doc;
}
/**
* Sets the XML text of this article.
*
* @param text the serialized XML text
*/
public void setText(String text) {
this.text = text;
}
/**
* Gets the current article-type
*
* @return the ArticleType
*/
public ArticleType getArticleType() {
return articleType;
}
/**
* Sets the current article-type
*
* @param articleType the ArticleType
*/
public void setArticleType(ArticleType articleType) {
this.articleType = articleType;
}
/**
* Returns the current status of this article
*
* @return the ArticleStatus
*/
public ArticleStatus getArticleStatus() {
return articleStatus;
}
/**
* Sets the current status of this article
*
* @param articleStatus the ArticeStatus
*/
public void setArticleStatus(ArticleStatus articleStatus) {
this.articleStatus = articleStatus;
}
/**
* Returns the number of characters in this article
*
* @return the current number of characters
*/
public int getCurrentNumberOfCharacters() {
return currentNumberOfCharacters;
}
/**
* Sets the current number of characters in this articel
*
* @param currentNumberOfCharacters the current number of characters
*/
public void setCurrentNumberOfCharacters(int currentNumberOfCharacters) {
this.currentNumberOfCharacters = currentNumberOfCharacters;
}
/**
* Returns the wanted number of characters in this article
*
* @return the number of wanted (planned) characters
*/
public int getWantedNumberOfCharacters() {
return wantedNumberOfCharacters;
}
/**
* Sets the wanted number of characters in this article
*
* @param wantedNumberOfCharacters the number of wanted characters
*/
public void setWantedNumberOfCharacters(int wantedNumberOfCharacters) {
this.wantedNumberOfCharacters = wantedNumberOfCharacters;
}
/**
* Get the value of wantedNumberOfPages.
*
* @return value of wantedNumberOfPages.
*/
public float getWantedNumberOfPages() {
return wantedNumberOfPages;
}
/**
* Set the value of wantedNumberOfPages.
*
* @param v Value to assign to wantedNumberOfPages.
*/
public void setWantedNumberOfPages(float v) {
this.wantedNumberOfPages = v;
}
/**
* Get the value of section.
*
* @return value of section.
*/
public Section getSection() {
return section;
}
/**
* Set the value of section.
*
* @param v Value to assign to section.
*/
public void setSection(Section v) {
this.section = v;
}
/**
* Set the value of canEditXML.
*
* @param v Value to assign to canEditXML.
*/
public void setCanEditXML(boolean v) {
this.canEditXML = v;
}
/**
* Sets the date this article was last saved
*
* @param lastSaved date of last save
*/
public void setLastSaved(Date lastSaved) {
this.lastSaved = lastSaved;
}
/**
* Returns the Date the article was last saved
*
* @return date of last save
*/
public Date getLastSaved() {
return lastSaved;
}
/**
* Creates a new article with a given ID (ie: from the database
*
* @param id The id of this article
*/
public Article(int id) {
this.id = id;
}
/**
* Creates a new, empty <code>Article</code> instance.
* All parameter has a <code>null</code> value.
*/
public Article() {
}
/**
* Returns the DOM-tree representing the text for this article.
*
* @return a <code>Document</code> value
*/
public Document getDocument() {
return mDoc;
}
/**
* Returns the document type for this article.
*
* @return a <code>String</code> value
*/
public String getDocumentType() {
try {
return mDoc.getDoctype().getName();
} catch (Exception e) {
Logger log = LoggerFactory.getLogger(getClass());
log.error("Exception getting document type!", e);
return null;
}
}
/**
* Returns true if this article has any text at all.
*
* @return a <code>boolean</code> value
*/
public boolean hasText() {
return text == null || text.length() > XML_MINIMUM;
}
/**
* Parses the text in the article and creates the DOM-tree in the
* variable mDoc.
*
* @return <code>true</code> if parsing succeeded.
*/
public boolean parseText() {
boolean outvar = true;
if (!this.hasText()) {
Logger log = LoggerFactory.getLogger(getClass());
log.error("Article got no text!");
outvar = false;
} else {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
factory.setIgnoringElementContentWhitespace(false);
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException pce) {
Logger log = LoggerFactory.getLogger(getClass());
log.error("Parser configuration exception", pce);
outvar = false;
}
StringReader stringReader = new StringReader(text);
try {
mDoc = builder.parse(new InputSource(stringReader));
} catch (SAXException se) {
Logger log = LoggerFactory.getLogger(getClass());
log.error("Error parsing", se);
outvar = false;
} catch (java.io.IOException ioe) {
Logger log = LoggerFactory.getLogger(getClass());
log.error("Error parsing", ioe);
outvar = false;
}
}
return outvar;
}
/**
* Returns the text. (ie. the serialized XML for this article)
*
* @return a <code>String</code> value
*/
public String getText() {
return text;
}
/**
* Serializes the DOM document and saves it to text.
*
* @return <code>true</code> if serialization succeded
*/
public boolean serialize() {
try {
StringWriter newText = new StringWriter();
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.ENCODING, "utf-8");
t.transform(new DOMSource(mDoc), new StreamResult(newText));
this.setText(newText.toString());
return true;
} catch (TransformerException e) {
Logger log = LoggerFactory.getLogger(getClass());
log.error("TransformerException serializing article");
return false;
}
}
/**
* Clone this article, except from the <code>mDoc</code> field.
* <code>mDoc</code> is always set to null, make sure that the
* xml is serialized by a call to {@link #serialize serialize()}
* before cloning.
*
* @return The clone.
*/
public Object clone() {
Article clone = new Article(this.id);
clone.articleName = articleName == null ? null : articleName;
clone.articleStatus = articleStatus == null ? null : (ArticleStatus) articleStatus.clone();
clone.articleType = articleType == null ? null : (ArticleType) articleType.clone();
clone.canEditXML = this.canEditXML;
clone.canView = this.canView;
clone.section = section == null ? null : (Section) section.clone();
clone.description = description == null ? null : description;
clone.journalist = journalist;
// FIXME: Should clone XML
clone.mDoc = null;
clone.photographer = photographer;
clone.publication = publication == null ? null : (Publication) publication.clone();
clone.text = text == null ? null : text;
clone.currentNumberOfCharacters = this.currentNumberOfCharacters;
clone.wantedNumberOfCharacters = this.wantedNumberOfCharacters;
clone.wantedNumberOfPages = this.wantedNumberOfPages;
clone.lastSaved = this.lastSaved;
return clone;
}
/**
* Suggests a file name in a quite crude way
*
* @param maxChars the maximum number of characters to suggest
N * @return the suggested file name
*/
public String suggestFileName(int maxChars) {
String suggestion = articleName;
StringBuilder clean = new StringBuilder();
for (int i = 0; i < suggestion.length(); i++) {
if (suggestion.charAt(i) == 'æ') {
clean.append("ae");
} else if (suggestion.charAt(i) == 'ø') {
clean.append("o");
} else if (suggestion.charAt(i) == 'å') {
clean.append("aa");
} else if (suggestion.charAt(i) == 'Æ') {
clean.append("Ae");
} else if (suggestion.charAt(i) == 'Ø') {
clean.append("O");
} else if (suggestion.charAt(i) == 'Å') {
clean.append("Aa");
} else if (Character.isLetter(suggestion.charAt(i))
|| Character.isDigit(suggestion.charAt(i))
|| Character.isWhitespace(suggestion.charAt(i))) {
clean.append(suggestion.charAt(i));
}
}
suggestion = clean.toString();
if (suggestion.length() > maxChars) {
suggestion = suggestion.substring(0, maxChars);
}
suggestion = suggestion.trim();
suggestion = suggestion.replace(' ', '_');
return suggestion;
}
}