org.pegadi.server.ServerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.pegadi.server.ServerImpl.java

Source

/**
 * 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.server;

import no.dusken.common.model.Person;
import no.dusken.common.service.PersonService;
import org.pegadi.games.Score;
import org.pegadi.model.*;
import org.pegadi.permissions.PermissionManager;
import org.pegadi.server.user.UserServer;
import org.pegadi.server.user.preferences.PreferenceServer;
import org.pegadi.sources.Category;
import org.pegadi.sources.Contact;
import org.pegadi.sources.Source;
import org.pegadi.sqlsearch.SearchTerm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ldap.core.LdapTemplate;

import java.io.Serializable;
import java.net.UnknownHostException;
import java.rmi.server.RemoteServer;
import java.rmi.server.ServerNotActiveException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * This is an implementation of the @see pegadi.Server interface. <p>
 *
 * This implementation basically instansiates a number of
 * sub-servers, each responsible for methods related to their scope
 * (articles, users, publications, etc.)<p>
 *
 * @author Jrgen Binningsb
 * @version $Id: ServerImpl.java 1998 2004-12-01 21:46:01Z bjorsnos
    
$
 */
public class ServerImpl implements org.pegadi.server.Server {

    /** Timeoutvalue for article lock (ms) */
    private final static int LOCK_TIMEOUT = 900000;

    /** Server for publication specific tasks */
    protected PublicationServer publicationServer;

    protected DisposalServer disposalServer;

    protected DispPageServer dispPageServer;

    /** Server for article specific tasks. */
    protected ArticleServer articleServer;

    protected ArticleTypeServer articleTypeServer;
    protected ArticleStatusServer articleStatusServer;

    protected SectionServer sectionServer;

    protected StylesheetServer stylesheetServer;

    /** Server for user-spesific tasks. */
    protected UserServer userServer;

    protected PreferenceServer preferenceServer;

    /** Server for game scores. */
    protected ScoreServer scoreServer;

    /** Server for game scores. */
    protected SourceServer sourceServer;

    /** Email server. */
    protected MailServer mailServer;

    /** Log server */
    protected LogServer logServer;

    protected PersonService personService;

    /** A list of active sessions. */
    Map<String, Session> sessions;

    /** The date this server was constructed. */
    private Date upSince;

    /** A table of ArticleLocks */
    private Hashtable<Integer, ArticleLock> lockedArticles;

    private final Logger log = LoggerFactory.getLogger(getClass());

    private PermissionManager permissionManager;
    private String webBase;
    private String webXml;

    private LdapTemplate ldapTemplate;
    private String userbase;

    /**
     * Logs some system parameters which are essential when deploying on a new system,
     * as they will show parameters which RMI uses server-side.
     * F.ex. all parameters are null the first time you install pegadi as a servlet under tomcat4.
     */
    private void rmiLog() {
        log.info("Value of java.rmi.server.hostname: {}", System.getProperty("java.rmi.server.hostname"));
        log.info("Value of java.rmi.server.codebase: {}", System.getProperty("java.rmi.server.codebase"));
        log.info("Value of java.rmi.server.useLocalHostname: {}",
                System.getProperty("java.rmi.server.useLocalHostname"));
    }

    public void setArticleServer(ArticleServer articleServer) {
        this.articleServer = articleServer;
    }

    public void setArticleTypeServer(ArticleTypeServer articleTypeServer) {
        this.articleTypeServer = articleTypeServer;
    }

    public void setSectionServer(SectionServer sectionServer) {
        this.sectionServer = sectionServer;
    }

    public void setStylesheetServer(StylesheetServer stylesheetServer) {
        this.stylesheetServer = stylesheetServer;
    }

    public void setUserServer(UserServer userServer) {
        this.userServer = userServer;
    }

    public void setPreferenceServer(PreferenceServer preferenceServer) {
        this.preferenceServer = preferenceServer;
    }

    public void setPublicationServer(PublicationServer publicationServer) {
        this.publicationServer = publicationServer;
    }

    public void setDisposalServer(DisposalServer disposalServer) {
        this.disposalServer = disposalServer;
    }

    public void setDispPageServer(DispPageServer dispPageServer) {
        this.dispPageServer = dispPageServer;
    }

    public void setSourceServer(SourceServer sourceServer) {
        this.sourceServer = sourceServer;
    }

    public void setMailServer(MailServer mailserver) {
        this.mailServer = mailserver;
    }

    public void setScoreServer(ScoreServer scoreServer) {
        this.scoreServer = scoreServer;
    }

    public void setLogServer(LogServer logServer) {
        this.logServer = logServer;
    }

    public void init() {

        rmiLog();
        lockedArticles = new Hashtable<Integer, ArticleLock>();
        upSince = new Date();

        try {
            log.info("Localhost is: {}, in my opinion", java.net.InetAddress.getLocalHost().getHostName());
        } catch (UnknownHostException e) {
            log.error("Unable to get address of localhost");
        }

        sessions = new ConcurrentHashMap<String, Session>();

    }

    /**
     * Returns the URL of the root of the web application
     */
    public String getWebBase(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return webBase;
    }

    /**
     * Returns the URL of the root of the web pages containing
     * templates/stylesheets etc.
     */
    public String getWebXMLRoot(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        //If webbase does not end with /, add one
        String mid = webBase.endsWith("/") ? "" : "/";
        return webBase + mid + webXml;
    }

    /**
     * Returns a lock for a given article, following these rules:
     * <ul>
     *  <li>If a lock for the article doesn't currently exist it is created and returned.
     *  <li>If a lock exists for the calling session, it is renewed and then returned.
     *  <li>If a lock exists for another session two things can happen:
     *   <ul>
     *     <li>If the lock has expired it is transferred to the calling session and returned.
     *     <li>If the lock is still valid it is transfered to the calling session if and only if the calling sessions username equals the username having the lock AND the parameter <code>transferIfSameUser</code> is true. This allows users to "hijack" their own locks.
     *   </ul>
     *  </li>
     *   </ul>
     * It's important that this method does not deny access to opening
     * an article. It is a client side responibility to allow or deny access
     * based on the lock returned by this method.
     * @param articleID the ID of the article to lock
     * @param sessionKey the sessionKey of the calling session
     *
     * @return an {@link org.pegadi.model.ArticleLock} describing the current lock state
     */
    public ArticleLock getArticleLock(int articleID, boolean transferIfSameUser, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);

        ArticleLock lock = lockedArticles.get(articleID);

        Session session;
        try {
            session = getVerifiedSession(sessionKey);
        } catch (NoAccessException e) {
            log.error("Could not get a verified session", e);
            return null;
        }

        // No lock exists for this article, create one and return it
        if (lock == null) {
            lock = new ArticleLock(articleID, sessionKey, getUser(session.getUsername(), sessionKey).getUsername(),
                    session.getHost());
            lockedArticles.put(articleID, lock);
            log.info("Creating new lock on article {} for user {} on {}",
                    new Object[] { articleID, session.getUsername(), session.getHost() });
            return lock;
        } else if (lock.getSessionKey().equals(sessionKey)) {
            // A lock is renewed when saving an article
            log.info("Renewing lock on article " + articleID + " for user " + session.getUsername() + " on "
                    + session.getHost());
            lock.renew();
            return lock;
        } else if (!lock.getSessionKey().equals(sessionKey)) {

            long age = (new Date()).getTime() - lock.getLastRenewed();

            // Other session has valid lock
            if (age < LOCK_TIMEOUT) {

                if (transferIfSameUser
                        && lock.getUsername().equals(getUser(session.getUsername(), sessionKey).getUsername())) {
                    log.info("firstTime1: {}", lock.getFirstLocked());
                    lock.transfer(sessionKey, getUser(session.getUsername(), sessionKey).getUsername(),
                            session.getHost());
                    log.info("firstTime2: {}", lock.getFirstLocked());
                    log.info("Same user has lock on article {} with age={}. Lock transfered!", articleID, age);
                    return lock;
                }

                log.info("Other session has lock on article {} with age={}.", articleID, age);
                return lock;

            } else {

                // Lock has expired, transfer to this session
                lock.transfer(sessionKey, getUser(session.getUsername(), sessionKey).getUsername(),
                        session.getHost());
                log.info("Expired lock on article {} transferred to  {} with age={}.",
                        new Object[] { articleID, session.getHost(), age });
                return lock;

            }
        }

        log.error("This should never happen! Check your code!");
        return null;

    }

    /**
     * Releases the lock on an article. This method must be called after closing an article.
     * @param articleID The ID of the article to unlock.
     * @param sessionKey The key of the session trying to unlock the article.
     */
    public void releaseArticleLock(int articleID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        ArticleLock lock = lockedArticles.get(articleID);

        if (lock != null) {
            log.info("Releasing lock on article {}", articleID);
            // Only the owner of the lock can release it.
            if (lock.getSessionKey().equals(sessionKey)) {
                lockedArticles.remove(articleID);
            }
        } else {
            log.info("Lock is null");
        }
    }

    /**
     * Returns an array of users who are allowed to edit a given article, excluding the owner of the article
     *
     * @param articleID The ID for the article to get a list of allowed users for.
     * @return An array of <code>User</code>s who are allowed to edit the article
     */

    public List<Person> getCoJournalistsForArticle(int articleID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return articleServer.getCoJournalistsForArticle(articleID);
    }

    /**
     * Sets the users allowed to edit a given article, excluding the owner. Note that all the previous co-journalists
     * who was set, is erased before the new ones are saved.
     * @param articleID The article to grant access to.
     * @param coJournalists The userIDs for the users allowed to edit the article
     */
    public void setCoJournalistsForArticle(int articleID, List<String> coJournalists, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);
        articleServer.setCoJournalistsForArticle(articleID, coJournalists);
    }

    public Date getUpSince() {
        return upSince;
    }

    // ================================================================
    // Sources methods
    //

    /**
     * Saves a source to the db. If the source is new (has ID==-1), the source
     * is inserted, if not it is updated.
     */
    public int saveSource(Source source, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return sourceServer.saveSource(source);
    }

    /**
     * Delete source from database
     */
    public void deleteSource(Source source, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        sourceServer.deleteSource(source);
    }

    /**
     * Searches a table for sources matching the search term
     */
    public List<Source> getSourcesBySearchTerm(SearchTerm term, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return sourceServer.getSourcesBySearchTerm(term);
    }

    /**
     * Returns a source by it's ID
     */
    public Source getSourceByID(int ID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return sourceServer.getSourceByID(ID);
    }

    /**
     * Return all categories
     */
    public List<Category> getSourceCategories(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return sourceServer.getSourceCategories();
    }

    /**
     * Add a category to database
     */
    public void addSourceCategory(Category newCategory, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        sourceServer.addSourceCategory(newCategory);
    }

    /**
     * Update a category in the database (for renaming)
     */
    public void updateSourceCategory(Category category, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        sourceServer.updateSourceCategory(category);
    }

    /**
     * Delete a category in the database
     */
    public void deleteSourceCategory(Category category, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        sourceServer.deleteSourceCategory(category);
    }

    /**
     * Returns all categories that the source with the ID is a mebmer of
     */
    public List<Category> getCategoriesBySource(int sourceID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return sourceServer.getCategoriesBySource(sourceID);
    }

    /**
     * updates the category memberships for the given source
     */
    public void updateSourceCategoryMemberships(int sourceID, List<Category> members, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);
        sourceServer.updateSourceCategoryMemberships(sourceID, members);
    }

    //
    // Server testing methods
    //
    /**
     * Sends an object to the server, and returns the same object. The object must implement
     * <code>serializable</code>.
     *
     * @param obj  An object
     * @return  The object returned
     */
    public Object ping(Object obj) {
        try {
            log.info("Ping from {}", RemoteServer.getClientHost());
        } catch (ServerNotActiveException sne) {
            log.error("Server not active, returning null.");
            return null;
        }

        // Log object
        if (obj != null) {
            log.info("Ping: Object is {}", obj.toString());
        } else {
            log.info("ping: Object is NULL!");
        }

        // Return
        if (obj instanceof Serializable) {
            return obj;
        } else {
            log.info("Ping: Object is not serializable, returning null.");
            return null;
        }
    }

    /**
     * Returns <code>true</code> if the server is alive. This method will always return
     * true if the client can contact the server, so instead of returning false an exception will
     * be thrown.
     *
     * @return <code>true</code> if the server is alive.
     * @see #ping(Object)
     */
    public boolean ping() {
        try {
            log.info("Ping from {}", RemoteServer.getClientHost());
        } catch (ServerNotActiveException sne) {
            log.error("Server not active, returning false.");
            return false;
        }
        return true;
    }

    /**
     * Returns all contacts made with a given source
     */
    public List<Contact> getContactsBySource(int sourceID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return sourceServer.getContactsBySource(sourceID);
    }

    /**
     * Send an email
     */
    public boolean sendmail(String from, String to, String subject, String text, String sessionKey)
            throws NoAccessException {
        List rcpt = new ArrayList<String>();
        rcpt.add(to);
        return sendmail(from, rcpt, subject, text, sessionKey);
    }

    public boolean sendmail(String from, List<String> to, String subject, String text, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);
        return mailServer.sendmail(from, to, subject, text);
    }

    // ================================
    // User- and login-specific methods
    // ================================

    /**
     * Authenticates the identitiy of the user. This method returns a session
     * key if successful, <code>null</code> on failure.<br>
     * The session key that is returned must be used on all subsequent calls
     * that require authentication.
     *
     * @param user  Username
     * @param pass  Password
     * @see org.pegadi.server.user.UserServerImpl#login
     * @see org.pegadi.server.Session
     *
     * @return A key for this session, <code>null</code> on failure.
     */
    public String login(String user, String pass) {
        log.info("Login: user {} trying to log in", user);
        String ID = userServer.login(user);
        log.info("Login: user ID returned for userServer is: {}", ID);
        if (ID != null) {
            boolean authenticated = false;
            if (System.getProperty("developerMode") == null) {
                log.debug("Tryin to authenticate user");
                try {
                    authenticated = ldapTemplate.authenticate(String.format("uid=%s,ou=people", user),
                            "objectClass=*", pass);
                    log.info("Login: user authenticated: {}", authenticated);
                } catch (Exception e) {
                    log.error("Caught exception while checking identity", e);
                }
            } else {
                log.info("In developermode, correct credentials not required!");
                authenticated = true;
            }

            if (authenticated) {

                String clientHost;
                try {
                    clientHost = RemoteServer.getClientHost();
                    log.info("Client host is: {}", clientHost);
                } catch (ServerNotActiveException sna) {
                    clientHost = "";
                }
                Session sess = addSession(ID, clientHost);
                log.debug("Logging in user {}. Clienthost is {}", user, clientHost);
                logServer.logLogin(sess.getKey(), clientHost, ID);
                return sess.getKey();

            } else {
                log.info("Login: Password check failed!");
                return null;
            }
        } else {
            log.info("Login: No user name '{}' found.", user);
            return null;
        }
    }

    /**
     * Logs out this session. This will free all resources used by the session.
     *
     * @param session  The session key.
     * @throws NoAccessException  If the session isn't valid.
     */
    public void logout(String session) throws NoAccessException {
        Session s = getVerifiedSession(session);

        log.info("Logging out user ID {} from {}", s.getUsername(), s.getHost());

        sessions.remove(s.getKey());
        logServer.logLogout(session);
    }

    /**
     * Creates a new session, and ensures that this session has an unique ID.
     *
     * @param ID    The user ID to create a session for.
     * @param host  The host of the user.
     */
    private Session addSession(String ID, String host) {

        Session sess = new Session(ID, host);

        String sessionKey = sess.getKey();
        log.info("Creating new session {} for user ID {} from {}", new Object[] { sessionKey, ID, host });

        sessions.put(sessionKey, sess);
        return sess;
    }

    /**
     * Returns a session. Alteratively, throws a NoAccessException if a
     * session with this key was not found, or the calling host and the
     * session host do not match.
     *
     * @param key  The key to find.
     * @return  The session for this key. This method will never return
     *          <code>null</code>, but instead throw a
     *          <code>NoAccessException</code> if the session wasn't found.
     * @throws NoAccessException  If a session with the given key wasn't found.
     */
    private Session getVerifiedSession(String key) throws NoAccessException {
        log.info("Verifying session {}", key);
        Session s = sessions.get(key);
        if (s != null) {
            String client = getSafeHost();
            if (s.getHost().equals(client)) {
                return s;
            } else {
                throw new NoAccessException("Client mismatch.");
            }

        }

        // No session found
        log.warn("getVerifiedSession: No session with key '{}' found.", key);
        throw new NoAccessException("No valid session!");
    }

    /**
     * Verifies the session. If the session isn't valid, an exception will be
     * thrown.<br>
     *
     * The implementation of this method is at the moment
     * {@link #getVerifiedSession getVerifiedSession}, but without the
     * return value.
     *
     * @param session  The session key.
     * @throws NoAccessException  If the session is invalid.
     * @see #getVerifiedSession
     */
    protected void verifySession(String session) throws NoAccessException {
        getVerifiedSession(session);
    }

    /**
     * Returns the callers host, or an empty string if an exception
     * occured when getting the host name. This is a convenience method
     * to use when we don't want to deal with the
     * {@link ServerNotActiveException java.rmi.server.ServerNotActiveException}
     * that can occur in a call to <code>getClientHost</code>.
     *
     * @return The host.
     */
    private String getSafeHost() {
        try {
            return RemoteServer.getClientHost();
        } catch (ServerNotActiveException e) {
            return "";
        }

    }

    /**
     * Returns the ID of the authtenticated user. The same result could be
     * obtanied bu calling <code>getSessionUser(key).getID()</code>, but this
     * method should be faster.
     *
     * @param sessionKey  The sessionKey key.
     * @return  The user's ID.
     * @throws NoAccessException  If the sessionKey object is invalid.
     */
    public String getUserID(String sessionKey) throws NoAccessException {
        return getVerifiedSession(sessionKey).getUsername();
    }

    /**
     * Returns the authenticated user. The authenticated user is the user owning
     * the sessionKey.
     *
     * @return The authenticated user
     * @throws NoAccessException  If the sessionKey object is invalid.
     */
    public Person getSessionUser(String sessionKey) throws NoAccessException {
        Session s = getVerifiedSession(sessionKey);

        return userServer.getUserByUsername(s.getUsername());
    }

    /**
     * Finds a user by the user's ID.
     *
     * @param ID  The ID to find.
     * @return  The user with the given ID.
     */
    public Person getUser(String ID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return userServer.getUserByUsername(ID);
    }

    /**
     * Finds a user by the user's name
     *
     * @param username  The username to find.
     * @return  The user with the given ID.
     */
    public Person getUserByUsername(String username, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return userServer.getUserByUsername(username);
    }

    @Override
    public Person getUserByLegacyId(Integer legacyId, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return userServer.getUserByLegacyId(legacyId);
    }

    /**
     * Return an array of all users.
     *
     * @param sessionKey A valid session.
     * @param  inactive  <code>true</code> if inactive users should be returned.
     * @return  An array of users.
     */
    public List<Person> getUsers(boolean inactive, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return userServer.getAllUsers(inactive);
    }

    /**
     * Save an user preference. The domain-key combination need not exist,
     * but if it exists it will be replaced.
     *
     * @param sessionKey A valid session.
     * @param domain  The preference domain.
     * @param key     The name of the preference.
     * @param value   The value of the preference.
     */
    public void savePreference(String domain, String key, String value, String sessionKey)
            throws NoAccessException {
        Session s = getVerifiedSession(sessionKey);
        String ID = s.getUsername();
        preferenceServer.savePreference(ID, domain, key, value);
    }

    /**
     * Get a single user preference. If there are no preference saved with
     * the domain-key combination for the user this method will return
     * <code>null</code>.
     *
     * @param domain  The preference domain.
     * @param key     The name of the preference.
     *
     * @param sessionKey A valid sessionKey.
     * @return        The value of the preference, or <code>null</code>.
     */
    public String getPreference(String domain, String key, String sessionKey) throws NoAccessException {
        String ID = getVerifiedSession(sessionKey).getUsername();
        return preferenceServer.getPreference(ID, domain, key);
    }

    /**
     * Get all the preferences for a domain. The method will always return
     * a valid <code>Properties</code> object, even if the domain does not
     * exists for this user.
     *
     * @param domain  The preference domain.
     *
     * @param sessionKey A valid sessionKey.
     * @return  All preferences for this domain. The object will be empty if no
     *          preferences were found.
     */
    public Properties getPreferences(String domain, String sessionKey) throws NoAccessException {
        String ID = getVerifiedSession(sessionKey).getUsername();
        return preferenceServer.getPreferences(ID, domain);
    }

    /**
     * Gets all the active Journalists.
     *
     * @return an array of <code>User</code>s
     */
    public List<Person> getJournalists(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return userServer.getJournalists();
    }

    /**
     * Gets all the active Photographers.
     *
     * @return an array of <code>User</code>s
     */
    public List<Person> getPhotographers(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return userServer.getPhotographers();
    }

    public boolean hasArticlePermission(String userId, int permissionId, int articleId, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);
        return permissionManager.hasArticlePermission(personService.getByUsername(userId), permissionId, articleId);
    }

    public boolean hasGlobalPermission(String userId, int permissionId, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);
        return permissionManager.hasGlobalPermission(personService.getByUsername(userId), permissionId);
    }

    // ===================================================================
    //  PUBLICATION
    //

    /**
     *  this method returns one publication to the client.
     */
    public Publication getPublicationByID(int ID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return publicationServer.getPublicationByID(ID);
    }

    /**
     * returns all the publications scheduled for releasing a given year
     */
    public List<Publication> getPublicationsByYear(int year, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return publicationServer.getPublicationsByYear(year);
    }

    /**
     * this method returns an array of Publications.
     * Active publications are defined as having a release-date higher
     * than the current date.
     */
    public List<Publication> getActivePublications(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return publicationServer.getActivePublications();
    }

    /**
     *  updates the values for this publication into the database
     */
    public int saveOrUpdatePublication(Publication pub, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return publicationServer.saveOrUpdatePublication(pub);
    }

    /**
     * Returns all years which have publications.
     *
     * @return an array of <code>int</code>'s
     */
    public List<Integer> getYearsWithPublications(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return publicationServer.getYearsWithPublications();
    }

    ///////////////////////////////////////////
    // Disposal
    ///////////////////////////////////////////
    public Disp getDisposalByID(int ID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return disposalServer.getDisposalByID(ID);
    }

    public Disp getDisposalByPublicationID(int publicationID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return disposalServer.getDisposalByPublicationID(publicationID);
    }

    public Disp createNewDisposal(int publicationID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return disposalServer.createNewDisposal(publicationID);
    }

    ///////////////////////////////////////////
    // DispPage
    ///////////////////////////////////////////
    public List<DispPage> getPagesByDispId(int dispId, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return dispPageServer.getPagesByDispId(dispId);
    }

    public DispPage createDispPage(DispPage dispPage, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return dispPageServer.createDispPage(dispPage);
    }

    public void saveDispPage(DispPage dispPage, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        dispPageServer.saveDispPage(dispPage);
    }

    public void saveDispPages(List<DispPage> dispPages, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        dispPageServer.saveDispPages(dispPages);
    }

    public void deleteDispPage(DispPage dispPage, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        dispPageServer.deleteDispPage(dispPage);
    }

    public List<DispSection> getDispSections(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return dispPageServer.getDispSections();
    }

    public List<DispSection> getActiveDispSections(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return dispPageServer.getActiveDispSections();
    }

    public DispSection getDispSectionById(int sectionId, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return dispPageServer.getDispSectionById(sectionId);
    }

    public void createDispSection(DispSection dispSection, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        dispPageServer.createDispSection(dispSection);
    }

    public void saveDispSection(DispSection dispSection, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        dispPageServer.saveDispSection(dispSection);
    }

    public void addArticleToPage(DispPage page, Article article, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        dispPageServer.addArticleToPage(page, article);
    }

    public void removeArticleFromPAge(DispPage page, Article article, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        dispPageServer.removeArticleFromPage(page, article);
    }

    ///////////////////////////////////////////
    // Article
    ///////////////////////////////////////////

    /**
     * Returns the Article with the given ID.
     *
     * @param ID       The article's ID.
     * @param sessionKey
     * @throws NoAccessException  If the session key is invalid.
     */
    public Article getArticleByID(int ID, String sessionKey) throws NoAccessException {
        Session s = getVerifiedSession(sessionKey);
        return articleServer.getArticleByID(personService.getByUsername(s.getUsername()), ID);
    }

    public List<Article> getArticlesByPageID(int pageId, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return articleServer.getArticlesByPageID(pageId);
    }

    public List<Article> getArticlesByDispID(int dispId, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return articleServer.getArticlesByDispID(dispId);
    }

    public List<Article> getArticlesBySearchTerm(SearchTerm searchTerm, String sessionKey)
            throws NoAccessException {
        Session s = getVerifiedSession(sessionKey);

        return articleServer.getArticlesBySearchTerm(personService.getByUsername(s.getUsername()), searchTerm);
    }

    /**
     * Returns all available article types.
     *
     * @return an array of <code>ArticleType</code>s.
     */
    public List<ArticleType> getArticleTypes(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return articleTypeServer.getArticleTypes();
    }

    /**
     * Returns all available article statuses.
     *
     * @return an array of  <code>ArticleStatus</code>s.
     */
    public List<ArticleStatus> getArticleStatuses(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return articleStatusServer.getArticleStatuses();
    }

    public int saveArticle(Article article, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        int save = articleServer.saveArticle(article);
        logServer.logSaveArticle(article);
        return save;
    }

    public boolean deleteArticle(int articleID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return articleServer.deleteArticle(articleID);
    }

    /**
     * Save the text of an open article. This implementation shold check if
     * the user is the owner and is editing the article.
     *
     * @param articleID  The ID of the article.
     * @param text  The text of the article.
     * @param charCount  The character count for the article.
     * @param sessionKey
     */
    public boolean saveArticleText(int articleID, String text, int charCount, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);
        Article a = new Article(articleID);
        a.setText(text);
        a.setCurrentNumberOfCharacters(charCount);
        return articleServer.saveArticleText(a);
    }

    /**
     * Heisann
     */

    public String getArticleLocation(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return articleServer.getArticleLocation().getAbsolutePath();
    }

    /**
     * Save the text of an open article.
     *
     * @param article  The article.
     * @param sessionKey
     */
    public boolean saveArticleText(Article article, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return articleServer.saveArticleText(article);
    }

    public Stylesheet getStylesheet(PublishingMediaEnum publishingMedia, Section section, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);
        return stylesheetServer.getStylesheet(publishingMedia, section);
    }

    public List<Section> getDepartments(String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return sectionServer.getDepartments();
    }

    /**
     * Returns the template for the given article. This method will return
     * <code>null</code> if the template isn't found.
     * @param articleID  The ID of the article.
     * @return  The template.
     */
    public String getTemplate(int articleID, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return articleServer.getTemplate(articleID);
    }

    // =========================================================================
    // Game spesific methods
    // =========================================================================

    //
    // Methods for recording scores
    //

    /**
     * Starts score recording for a new game. The <code>Score</code> object that is
     * returned <i>must</i> be used when calling {@link Server#updateScore } and
     * {@link Server#endGame }, as each score has an unique ID.
     *
     * @param domain  The domain for the game.
     * @param sessionKey
     * @return  A new Score object, with the score set to 0. If the domain is not known,
     *          this method will return <code>null</code>.
     */
    public Score startGame(String domain, String sessionKey) throws NoAccessException {
        Session s = getVerifiedSession(sessionKey);
        return scoreServer.startGame(userServer.getUserByUsername(s.getUsername()), domain);
    }

    /**
     * Updates the score for a running game. The <code>Score</code> object must have the
     * same ID as the object returned by {@link Server#startGame}, and the client must set the
     * new value for score before updating.
     *
     * @param score  The current score.
     * @param sessionKey
     */
    public void updateScore(Score score, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        scoreServer.updateScore(score);
    }

    /**
     * Records the final score for a game.The <code>Score</code> object must have the
     * same ID as the object returned by {@link Server#startGame}, and the client must set the
     * final value for the score.
     *
     * @param score  The final score.
     * @param sessionKey
     * @return  The same score object, with the <code>active</code> property set to false.
     * @see org.pegadi.games.Score#isActive
     */
    public Score endGame(Score score, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        return scoreServer.endGame(score);
    }

    /**
     * Cancels a game in progress.
     *
     * @param score  The game to cancel.
     * @param sessionKey
     */
    public void cancelGame(Score score, String sessionKey) throws NoAccessException {
        verifySession(sessionKey);
        scoreServer.cancelGame(getVerifiedSession(sessionKey).getUsername(), score);
    }

    //
    // Method for getting score lists
    //

    /**
     * Returns the <code>count</code> best scores ever.
     *
     * @param count   Number of scores to return.
     * @param domain  The game domain
     * @return  List of scores.
     * @see org.pegadi.games.Score
     */
    public List<? extends Score> getHighScore(String domain, int count, boolean activesOnly, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);
        return scoreServer.getHighScore(domain, count, activesOnly);
    }

    /**
     * Returns the <code>count</code> best scores for the given user ID.
     *
     * @param userID  user ID to return scores for.
     * @param count   Number of scores to return.
     * @param domain  The game domain
     * @return  List of scores.
     * @see org.pegadi.games.Score
     */
    public List<? extends Score> getUserScoreByUserID(String domain, String userID, int count, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);
        return scoreServer.getUserScore(domain, userID, count);
    }

    /**
     * Returns the <code>count</code> best scores for the user with this session.
     * This is a convenience method to get scores for the logged in user.
     * If the session is invalid, this method will return <code>null</code>.
     *
     * @param sessionKey Sessionto return scores for.
     * @param count   Number of scores to return.
     * @param domain  The game domain
     * @return  List of scores.
     * @see org.pegadi.games.Score
     */
    public List<? extends Score> getUserScore(String domain, int count, String sessionKey)
            throws NoAccessException {
        Session s = getVerifiedSession(sessionKey);
        return scoreServer.getUserScore(domain, s.getUsername(), count);
    }

    /**
     * Returns the <code>count</code> best scores the given date.
     *
     * @param day     The date to return scores from.
     * @param count   Number of scores to return.
     * @param domain  The game domain
     * @return  List of scores.
     * @see org.pegadi.games.Score
     */
    public List<? extends Score> getDayScore(String domain, Date day, int count, String sessionKey)
            throws NoAccessException {
        verifySession(sessionKey);
        return scoreServer.getDayScore(domain, day, count);
    }

    public void setPermissionManager(PermissionManager permissionManager) {
        this.permissionManager = permissionManager;
    }

    public void setWebBase(String webBase) {
        this.webBase = webBase;
    }

    public void setWebXml(String webXml) {
        this.webXml = webXml;
    }

    public void setPersonService(PersonService personService) {
        this.personService = personService;
    }

    public void setLdapTemplate(LdapTemplate ldapTemplate) {
        this.ldapTemplate = ldapTemplate;
    }

    public void setArticleStatusServer(ArticleStatusServer articleStatusServer) {
        this.articleStatusServer = articleStatusServer;
    }

    public void setUserbase(String userbase) {
        this.userbase = userbase;
    }
}