/* * ContentSite.java * * This work is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * This work 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * * Copyright (c) 2004-2006 Per Cederberg. All rights reserved. */ package org.liquidsite.core.content; import java.util.ArrayList; import org.liquidsite.core.data.ContentData; import org.liquidsite.core.data.ContentPeer; import org.liquidsite.core.data.ContentQuery; import org.liquidsite.core.data.DataObjectException; import org.liquidsite.core.data.DataSource; import org.liquidsite.util.log.Log; /** * A web site. * * @author Per Cederberg, <per at percederberg dot net> * @version 1.0 */ public class ContentSite extends Content { /** * The class logger. */ private static final Log LOG = new Log(ContentSite.class); /** * The protocol content attribute. */ private static final String PROTOCOL_ATTRIBUTE = "PROTOCOL"; /** * The host content attribute. */ private static final String HOST_ATTRIBUTE = "HOST"; /** * The port content attribute. */ private static final String PORT_ATTRIBUTE = "PORT"; /** * The directory content attribute. */ private static final String DIRECTORY_ATTRIBUTE = "DIRECTORY"; /** * The flags content attribute. */ private static final String FLAGS_ATTRIBUTE = "FLAGS"; /** * The administration site flag. */ private static final int ADMIN_FLAG = 1; /** * Returns an array of content site in the specified domain. Only * the latest revision of each content object will be returned. * This method differs from the results returned by a search with * findByCategory() in that offline objects can also be returned. * * @param manager the content manager to use * @param domain the domain * * @return an array of content site objects found * * @throws ContentException if the database couldn't be accessed * properly */ protected static ContentSite[] findByDomain(ContentManager manager, Domain domain) throws ContentException { DataSource src = getDataSource(manager); ContentQuery query; ArrayList list; ContentData data; ContentSite[] res; try { query = new ContentQuery(domain.getName()); query.requireParent(0); query.requireCategory(SITE_CATEGORY); query.requirePublished(!manager.isAdmin()); list = ContentPeer.doSelectByQuery(src, query); res = new ContentSite[list.size()]; for (int i = 0; i < list.size(); i++) { data = (ContentData) list.get(i); res[i] = new ContentSite(manager, data, src); } return res; } catch (DataObjectException e) { LOG.error(e.getMessage()); throw new ContentException(e); } finally { src.close(); } } /** * Creates a new site with default values. * * @param manager the content manager to use * @param domain the site domain */ public ContentSite(ContentManager manager, Domain domain) { super(manager, domain, Content.SITE_CATEGORY); setAttribute(PROTOCOL_ATTRIBUTE, "http"); setAttribute(HOST_ATTRIBUTE, "*"); setAttribute(PORT_ATTRIBUTE, "0"); setAttribute(DIRECTORY_ATTRIBUTE, "/"); setAttribute(FLAGS_ATTRIBUTE, "0"); } /** * Creates a new site. * * @param manager the content manager to use * @param data the content data object * @param src the data source to use * * @throws ContentException if the database couldn't be accessed * properly */ protected ContentSite(ContentManager manager, ContentData data, DataSource src) throws ContentException { super(manager, data, src); } /** * Returns a string representation of this object. * * @return a string representation of this object */ public String toString() { StringBuffer buffer = new StringBuffer(); int port = getPort(); String dir = getDirectory(); buffer.append(getProtocol()); buffer.append("://"); if (getHost().equals("*")) { buffer.append("<*>"); } else { buffer.append(getHost()); } if (port == 0) { buffer.append(":<*>"); } else if (port == 80 && getProtocol().equals("http")) { // Skip printing port } else if (port == 443 && getProtocol().equals("https")) { // Skip printing port } else { buffer.append(":"); buffer.append(port); } buffer.append(dir); return buffer.toString(); } /** * Returns the site protocol * * @return the site protocol */ public String getProtocol() { return getAttribute(PROTOCOL_ATTRIBUTE); } /** * Sets the site protocol. * * @param protocol the new site protocol */ public void setProtocol(String protocol) { setAttribute(PROTOCOL_ATTRIBUTE, protocol); } /** * Returns the host name or IP address. * * @return the host name, or * "*" if any host matches this site */ public String getHost() { return getAttribute(HOST_ATTRIBUTE); } /** * Sets the host name or IP address. This value must be the fully * qualified name with domain used in the URL:s to the site. * * @param host the new host name, or "*" for any */ public void setHost(String host) { setAttribute(HOST_ATTRIBUTE, host); } /** * Returns the port number. * * @return the port number, or * zero (0) if any port matches this site */ public int getPort() { return Integer.parseInt(getAttribute(PORT_ATTRIBUTE)); } /** * Sets the port number. * * @param port the new port number, or zero (0) for any */ public void setPort(int port) { setAttribute(PORT_ATTRIBUTE, String.valueOf(port)); } /** * Returns the base directory. The base directory always starts * and ends with a '/' character. * * @return the base directory */ public String getDirectory() { return getAttribute(DIRECTORY_ATTRIBUTE); } /** * Sets the base directory. * * @param directory the new base directory */ public void setDirectory(String directory) { if (directory == null) { directory = "/"; } if (!directory.startsWith("/")) { directory = "/" + directory; } if (!directory.endsWith("/")) { directory += "/"; } setAttribute(DIRECTORY_ATTRIBUTE, directory); } /** * Checks if the admin flag is set. * * @return true if the admin flag is set, or * false otherwise */ public boolean isAdmin() { int flags = Integer.parseInt(getAttribute(FLAGS_ATTRIBUTE)); return (flags & ADMIN_FLAG) > 0; } /** * Sets the admin flag. * * @param admin the new admin flag */ public void setAdmin(boolean admin) { int flags = Integer.parseInt(getAttribute(FLAGS_ATTRIBUTE)); if (admin) { flags = (flags | ADMIN_FLAG); } else { flags = (flags & ~ADMIN_FLAG); } setAttribute(FLAGS_ATTRIBUTE, String.valueOf(flags)); } /** * Checks if a set of request parameters matches this site. * * @param protocol the request protocol * @param host the request host name (server name) * @param port the request (server) port * * @return true if the request parameters match this site, or * false otherwise */ public boolean isMatch(String protocol, String host, int port) { return getProtocol().equals(protocol) && (getHost().equals(host) || getHost().equals("*")) && (getPort() == port || getPort() == 0); } /** * Checks if a set of request parameters matches this site. * * @param protocol the request protocol * @param host the request host name (server name) * @param port the request (server) port * @param path the request path * * @return true if the request parameters match this site, or * false otherwise */ public boolean isMatch(String protocol, String host, int port, String path) { return isMatch(protocol, host, port) && path.startsWith(getDirectory()); } /** * Matches a set of request parameters to this site. This method * returns a numeric value that is higher for better matches. If * the request parameters didn't match at all, zero (0) is always * returned. The matching algorithm gives priority to exact * matches for host and port, and longer matches for paths. An * exact match for host or port is also always preferred over a * longer path match. * * @param protocol the request protocol * @param host the request host name (server name) * @param port the request (server) port * @param path the request path * * @return the match value (higher is better), or * zero (0) for no match */ public int match(String protocol, String host, int port, String path) { int result = 0; // Check protocol match if (!getProtocol().equals(protocol)) { return 0; } // Check host match if (getHost().equals(host)) { result += 10000; } else if (getHost().equals("*")) { result += 0; } else { return 0; } // Check port match if (getPort() == port) { result += 1000; } else if (getPort() == 0) { result += 0; } else { return 0; } // Check directory match if (path.startsWith(getDirectory())) { result += getDirectory().length(); } else { return 0; } return result; } /** * Validates the object data before writing to the database. * * @throws ContentException if the object data wasn't valid */ protected void doValidate() throws ContentException { Content[] children; ContentSite site; super.doValidate(); if (!getProtocol().equals("http") && !getProtocol().equals("https")) { throw new ContentException("protocol must be 'http' or 'https'"); } else if (getHost().equals("")) { throw new ContentException("no host name set for site"); } if (getParent() != null) { throw new ContentException("site cannot be located inside " + "another site or folder"); } children = InternalContent.findByParent(getContentManager(), getDomain()); for (int i = 0; i < children.length; i++) { if (children[i].getId() != getId() && children[i].getName().equals(getName())) { throw new ContentException( "another object with the same name already exists"); } if (children[i] instanceof ContentSite) { site = (ContentSite) children[i]; if (site.getId() != getId() && site.getProtocol().equals(getProtocol()) && site.getHost().equals(getHost()) && site.getPort() == getPort() && site.getDirectory().equals(getDirectory())) { throw new ContentException( "an identical site definition already exists"); } } } } }