/*
* Copyright 2000-2001,2004 The Apache Software Foundation.
*
* 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.apache.jetspeed.services.psmlmanager;
//Jetspeed stuff
import org.apache.jetspeed.om.profile.ProfileLocator;
import org.apache.jetspeed.om.profile.QueryLocator;
import org.apache.jetspeed.util.FileCopy;
import org.apache.jetspeed.util.DirectoryUtils;
import org.apache.jetspeed.services.Profiler;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;
import org.apache.jetspeed.services.JetspeedSecurity;
import org.apache.jetspeed.services.resources.JetspeedResources;
//Castor defined API
import org.apache.jetspeed.om.profile.Portlets;
import org.apache.jetspeed.om.profile.*;
//turbine stuff
import org.apache.turbine.services.TurbineBaseService;
import org.apache.turbine.services.InitializationException;
import org.apache.turbine.services.TurbineServices;
import org.apache.turbine.services.servlet.TurbineServlet;
import org.apache.turbine.services.resources.ResourceService;
import org.apache.turbine.services.servlet.ServletService;
import org.apache.jetspeed.om.security.JetspeedUser;
import org.apache.jetspeed.om.security.Role;
import org.apache.jetspeed.om.security.JetspeedRoleFactory;
import org.apache.jetspeed.om.security.Group;
import org.apache.jetspeed.om.security.JetspeedGroupFactory;
import org.apache.jetspeed.om.security.JetspeedUserFactory;
//castor support
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.xml.ValidationException;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
// serialization support
import org.apache.xml.serialize.Serializer;
import org.apache.xml.serialize.XMLSerializer;
import org.apache.xml.serialize.OutputFormat;
//standard java stuff
import java.io.File;
import java.io.Reader;
import java.io.FileReader;
import java.io.Writer;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;
import javax.servlet.ServletConfig;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.jetspeed.cache.FileCache;
import org.apache.jetspeed.cache.FileCacheEventListener;
import org.apache.jetspeed.cache.FileCacheEntry;
/**
* This service is responsible for loading and saving PSML documents.
*
* @author <a href="mailto:raphael@apache.org">Rapha謖 Luta</a>
* @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
* @author <a href="mailto:sgala@apache.org">Santiago Gala</a>
* @version $Id: CastorPsmlManagerService.java,v 1.44 2004/03/31 00:23:02 jford Exp $
*/
public class CastorPsmlManagerService extends TurbineBaseService
implements FileCacheEventListener,
PsmlManagerService
{
/**
* Static initialization of the logger for this class
*/
private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(CastorPsmlManagerService.class.getName());
// resource path constants
protected static final String PATH_GROUP = "group";
protected static final String PATH_ROLE = "role";
protected static final String PATH_USER = "user";
// configuration keys
protected final static String CONFIG_ROOT = "root";
protected final static String CONFIG_EXT = "ext";
protected final static String CONFIG_SCAN_RATE = "scanRate";
protected final static String CONFIG_CACHE_SIZE = "cacheSize";
// default configuration values
public final static String DEFAULT_ROOT = "/WEB-INF/psml";
public final static String DEFAULT_EXT = ".psml";
// default resource
public final static String DEFAULT_RESOURCE = "default.psml";
// the root psml resource directory
protected String root;
// base store directory
protected File rootDir = null;
// file extension
protected String ext;
/** The documents loaded by this manager */
protected FileCache documents = null;
/** the output format for pretty printing when saving registries */
protected OutputFormat format = null;
/** the base refresh rate for documents */
protected long scanRate = 1000 * 60; // every minute
/** the default cache size */
protected int cacheSize = 100;
/** the import/export consumer service **/
protected PsmlManagerService consumer = null;
protected boolean importFlag = false;
// castor mapping
public static final String DEFAULT_MAPPING = "${webappRoot}/WEB-INF/conf/psml-mapping.xml";
protected String mapFile = null;
/** the Castor mapping file name */
protected Mapping mapping = null;
/** The default encoding used to serialize PSML files to disk */
protected String defaultEncoding = JetspeedResources.getString(JetspeedResources.CONTENT_ENCODING_KEY, "utf-8");
/**
* This is the early initialization method called by the
* Turbine <code>Service</code> framework
*/
public void init( ServletConfig conf ) throws InitializationException
{
if (getInit())
{
return;
}
//Ensure that the servlet service is initialized
TurbineServices.getInstance().initService(ServletService.SERVICE_NAME, conf);
// get configuration parameters from Jetspeed Resources
ResourceService serviceConf = ((TurbineServices)TurbineServices.getInstance())
.getResources(PsmlManagerService.SERVICE_NAME);
// get the PSML Root Directory
this.root = serviceConf.getString( CONFIG_ROOT, DEFAULT_ROOT );
this.rootDir = new File(root);
//If the rootDir does not exist, treat it as context relative
if ( !rootDir.exists() )
{
try
{
this.rootDir = new File(conf.getServletContext().getRealPath(root));
}
catch (Exception e)
{
// this.rootDir = new File("./webapp" + this.rootDir.toString());
}
}
//If it is still missing, try to create it
if (!rootDir.exists())
{
try
{
rootDir.mkdirs();
}
catch (Exception e)
{
}
}
// get default extension
this.ext = serviceConf.getString( CONFIG_EXT, DEFAULT_EXT );
// create the serializer output format
this.format = new OutputFormat();
format.setIndenting(true);
format.setIndent(4);
format.setLineWidth(0);
// psml castor mapping file
mapFile = serviceConf.getString("mapping",DEFAULT_MAPPING);
mapFile = TurbineServlet.getRealPath( mapFile );
loadMapping();
this.scanRate = serviceConf.getLong(CONFIG_SCAN_RATE, this.scanRate);
this.cacheSize= serviceConf.getInt(CONFIG_CACHE_SIZE, this.cacheSize);
documents = new FileCache(this.scanRate, this.cacheSize);
documents.addListener(this);
documents.startFileScanner();
//Mark that we are done
setInit(true);
// Test
//testCases();
}
/** Late init method from Turbine Service model */
public void init() throws InitializationException
{
while( !getInit() )
{
//Not yet...
try
{
Thread.sleep( 500 );
}
catch (InterruptedException ie )
{
logger.error("Exception", ie);
}
}
}
/**
* This is the shutdown method called by the
* Turbine <code>Service</code> framework
*/
public void shutdown()
{
documents.stopFileScanner();
}
/**
* Returns a PSML document of the given name.
* For this implementation, the name must be the document
* URL or absolute filepath
*
* @deprecated
* @param name the name of the document to retrieve
*/
public PSMLDocument getDocument( String name )
{
if (name == null)
{
String message = "PSMLManager: Must specify a name";
logger.error( message );
throw new IllegalArgumentException( message );
}
if (logger.isDebugEnabled())
{
logger.debug( "PSMLManager: asked for " + name );
}
PSMLDocument doc = null;
doc = (PSMLDocument)documents.getDocument(name);
if (doc == null)
{
doc = loadDocument(name);
synchronized (documents)
{
// store the document in the hash and reference it to the watcher
try
{
documents.put(name, doc);
}
catch (java.io.IOException e)
{
logger.error("Error putting document", e);
}
}
}
return doc;
}
/**
* Returns a cached PSML document for the given locator
*
* @param locator The locator descriptor of the document to be retrieved.
* @return PSML document from cache (or disk if not yet cached)
*/
public PSMLDocument getDocument( ProfileLocator locator)
{
return getDocument(locator, true);
}
/**
* Returns a PSML document for the given locator
*
* @param locator The locator descriptor of the document to be retrieved.
* @param getCached Look in the cache (true) or umarshall a fresh copy from disk (false)
* @return
*/
protected PSMLDocument getDocument( ProfileLocator locator, boolean getCached )
{
if (locator == null)
{
String message = "PSMLManager: Must specify a name";
logger.error( message );
throw new IllegalArgumentException( message );
}
File base = this.rootDir;
String path = mapLocatorToFile(locator);
File file = new File(base, path);
String name = null;
try
{
name = file.getCanonicalPath();
}
catch (IOException e)
{
logger.error("PSMLManager: unable to resolve file path for "+ file);
}
if (logger.isDebugEnabled())
{
logger.debug("PSMLManager: calculated resource:" + path + ". Base: " + base + " File: " + name);
}
PSMLDocument doc = null;
Profile profile = null;
if (getCached == true)
{
profile = (Profile)documents.getDocument(name);
}
if (profile == null)
{
doc = loadDocument(name);
if (null == doc)
{
if (logger.isWarnEnabled())
{
logger.warn( "PSMLManager: " + name + " not found, returning null document" );
}
return null;
}
synchronized (documents)
{
// store the document in the hash and reference it to the watcher
Profile newProfile = createProfile(locator);
newProfile.setDocument(doc);
try
{
documents.put(name, newProfile);
}
catch (IOException e)
{
logger.error("Error putting document", e);
}
}
}
else
{
doc = profile.getDocument();
}
return doc;
}
/**
* Loads a PSML document from disk bypassing the cache
*
* @param locator
* @return PSML document from disk
*/
public PSMLDocument refresh(ProfileLocator locator)
{
if (logger.isDebugEnabled())
{
logger.debug("CastorPsmlManagerService: psml document refreshed from disk: " + locator.getPath());
}
return getDocument(locator, false);
}
/**
* Load a PSMLDOcument from disk
*
* @param fileOrUrl a String representing either an absolute URL or an
* absolute filepath
*/
protected PSMLDocument loadDocument(String fileOrUrl)
{
PSMLDocument doc = null;
if (fileOrUrl!=null)
{
if (!fileOrUrl.endsWith(DEFAULT_EXT))
{
fileOrUrl = fileOrUrl.concat(DEFAULT_EXT);
}
// load the document and add it to the watcher
// we'll assume the name is the the location of the file
File f = getFile(fileOrUrl);
if (null == f)
return null;
doc = new BasePSMLDocument();
doc.setName(fileOrUrl);
// now that we have a file reference, try to load the serialized PSML
Portlets portlets = null;
try
{
DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbfactory.newDocumentBuilder();
Document d = builder.parse(f);
Unmarshaller unmarshaller = new Unmarshaller(this.mapping);
portlets = (Portlets)unmarshaller.unmarshal((Node) d);
doc.setPortlets(portlets);
}
catch (IOException e)
{
logger.error("PSMLManager: Could not load the file "+f.getAbsolutePath(), e);
doc = null;
}
catch (MarshalException e)
{
logger.error("PSMLManager: Could not unmarshal the file "+f.getAbsolutePath(), e);
doc = null;
}
catch (MappingException e)
{
logger.error("PSMLManager: Could not unmarshal the file "+f.getAbsolutePath(), e);
doc = null;
}
catch (ValidationException e)
{
logger.error("PSMLManager: document "+f.getAbsolutePath()+" is not valid", e);
doc = null;
}
catch (ParserConfigurationException e)
{
logger.error("PSMLManager: Could not load the file "+f.getAbsolutePath(), e);
doc = null;
}
catch (SAXException e)
{
logger.error("PSMLManager: Could not load the file "+f.getAbsolutePath(), e);
doc = null;
}
}
return doc;
}
/** Store the PSML document on disk, using its locator
*
* @param profile the profile locator description.
* @return true if the operation succeeded
*/
public boolean store(Profile profile)
{
PSMLDocument doc = profile.getDocument();
File base = this.rootDir;
String path = mapLocatorToFile(profile);
File file = new File(base, path);
String fullpath = null;
try
{
fullpath = file.getCanonicalPath();
}
catch (IOException e)
{
logger.error("PSMLManager: unable to resolve file path for "+ file);
}
boolean ok = saveDocument(fullpath, doc);
// update it in cache
synchronized (documents)
{
try
{
documents.put(fullpath, profile);
}
catch (IOException e)
{
logger.error("Error storing document", e);
}
}
return ok;
}
/** Save the PSML document on disk, using its name as filepath
* @deprecated
* @param doc the document to save
*/
public boolean saveDocument(PSMLDocument doc)
{
return saveDocument(doc.getName(), doc);
}
/** Save the PSML document on disk to the specififed fileOrUrl
*
* @param fileOrUrl a String representing either an absolute URL
* or an absolute filepath
* @param doc the document to save
*/
public boolean saveDocument(String fileOrUrl, PSMLDocument doc)
{
boolean success = false;
if (doc == null) return false;
File f = getFile(fileOrUrl);
if (f == null)
{
f = new File(fileOrUrl);
}
OutputStreamWriter writer = null;
FileOutputStream fos = null;
try
{
String encoding = this.defaultEncoding;
fos = new FileOutputStream(f);
writer = new OutputStreamWriter(fos, encoding);
save(writer, doc.getPortlets());
success = true;
}
catch (MarshalException e)
{
logger.error("PSMLManager: Could not marshal the file "+f.getAbsolutePath(), e);
}
catch (MappingException e)
{
logger.error("PSMLManager: Could not marshal the file "+f.getAbsolutePath(), e);
}
catch (ValidationException e)
{
logger.error("PSMLManager: document "+f.getAbsolutePath()+" is not valid", e);
}
catch (IOException e)
{
logger.error("PSMLManager: Could not save the file "+f.getAbsolutePath(), e);
}
catch (Exception e)
{
logger.error("PSMLManager: Error while saving "+f.getAbsolutePath(), e);
}
finally
{
try { writer.close(); } catch (IOException e) {}
try { if(fos != null) { fos.close(); } } catch (IOException e) {}
}
return success;
}
/** Deserializes a PSML structure read from the reader using Castor
* XML unmarshaller
*
* @param reader the reader to load the PSML from
* @param the loaded portlets structure or null
*/
protected Portlets load(Reader reader)
throws IOException, MarshalException, ValidationException, MappingException
{
Unmarshaller unmarshaller = new Unmarshaller(this.mapping);
Portlets portlets = (Portlets)unmarshaller.unmarshal(reader);
return portlets;
}
protected void loadMapping()
throws InitializationException
{
// test the mapping file and create the mapping object
if (mapFile != null)
{
File map = new File(mapFile);
if (logger.isDebugEnabled())
{
logger.debug("PSMLManager: Loading psml mapping file "+mapFile);
}
if (map.exists() && map.isFile() && map.canRead())
{
try
{
mapping = new Mapping();
InputSource is = new InputSource( new FileReader(map) );
is.setSystemId( mapFile );
mapping.loadMapping( is );
}
catch (Exception e)
{
logger.error("PSMLManager: Error in psml mapping creation", e);
throw new InitializationException("Error in mapping",e);
}
}
else
{
throw new InitializationException("PSML Mapping not found or not a file or unreadable: "+mapFile);
}
}
}
/** Serializes a PSML structure using the specified writer with Castor
* XML marshaller and a Xerces serializer for pretty printing
*
* @param writer the writer to use for serialization
* @param portlets the structure to save
*/
protected void save(Writer writer, Portlets portlets)
throws IOException, MarshalException, ValidationException, MappingException
{
String encoding = this.defaultEncoding;
if (portlets != null)
{
format.setEncoding(encoding);
Serializer serializer = new XMLSerializer(writer, format);
Marshaller marshaller = new Marshaller(serializer.asDocumentHandler());
marshaller.setMapping(this.mapping);
marshaller.marshal(portlets);
}
}
/** Tests wether the passed argument is an URL string or a file name
* and returns the corresponding file object, using diskcache for
* remote URLs
*
* @param fileOrUrl the URL string or file path
* @return a File object. This file may not exist on disk.
*/
protected File getFile(String fileOrUrl)
{
File f = null;
f = new File(fileOrUrl);
if (f.exists())
{
return f;
}
return null;
}
/** Create a new document.
*
* @param profile The description and default value for the new document.
* @return The newly created document;
*/
public PSMLDocument createDocument( Profile profile )
{
File base = this.rootDir;
String path = mapLocatorToFile((ProfileLocator)profile);
if (logger.isDebugEnabled())
{
logger.debug("PSMLManager: Create document for profile " + profile +", calculated path: " + path);
}
File file = new File(base, path);
String name = null;
try
{
name = file.getCanonicalPath();
}
catch (IOException e)
{
logger.error("PSMLManager: unable to resolve file path for "+ file);
}
PSMLDocument template = profile.getDocument();
PSMLDocument doc = new BasePSMLDocument( name, template.getPortlets() );
try
{
String parent = file.getParent();
File filePath = new File(parent);
filePath.mkdirs();
if (template.getName() != null)
{
try
{
File source = new File(template.getName());
if (source.exists())
{
FileCopy.copy( template.getName(), name );
}
}
catch (Exception e)
{}
}
else
{
doc.setName(name);
}
saveDocument(doc);
}
catch (Exception e)
{
logger.error("PSMLManager: Failed to save document: " , e);
}
return doc;
}
/** Given a ordered list of locators, find the first document matching
* a profile locator, starting from the beginning of the list and working
* to the end.
*
* @param locator The ordered list of profile locators.
*/
public PSMLDocument getDocument( List locators )
{
PSMLDocument doc=null;
Iterator i = locators.iterator();
while ((doc==null)&&(i.hasNext()))
{
doc=getDocument((ProfileLocator)i.next());
}
return doc;
}
/** Removes a document.
*
* @param locator The description of the profile resource to be removed.
*/
public void removeDocument( ProfileLocator locator )
{
// remove a single document
String fileName = mapLocatorToFile(locator);
File base = this.rootDir;
File file = new File(base, fileName);
String name = null;
try
{
name = file.getCanonicalPath();
}
catch (IOException e)
{
logger.error("PSMLManager: unable to resolve file path for "+ file);
}
synchronized (documents)
{
documents.remove(name);
}
file.delete();
}
/** Removes all documents for a given user.
*
* @param user The user object.
*/
public void removeUserDocuments( JetspeedUser user )
{
ProfileLocator locator = Profiler.createLocator();
locator.setUser(user);
StringBuffer buffer = new StringBuffer();
buffer.append(PATH_USER);
String name = user.getUserName();
if (null != name && name.length() > 0)
{
buffer.append(File.separator)
.append(name);
}
else
return; // don't delete the entire user directories
String path = buffer.toString();
File base = this.rootDir;
File file = new File(base, path);
try
{
name = file.getCanonicalPath();
}
catch (IOException e)
{
logger.error("PSMLManager: unable to resolve file path for "+ file);
}
synchronized (documents)
{
DirectoryUtils.rmdir(name);
Iterator it = documents.getIterator();
while (it.hasNext())
{
FileCacheEntry entry = (FileCacheEntry)it.next();
if (null == entry)
{
continue;
}
Profile profile = (Profile)entry.getDocument();
if (null == profile)
{
continue;
}
JetspeedUser pUser = profile.getUser();
if (null != pUser && pUser.getUserName().equals(user.getUserName()))
{
documents.remove(profile.getDocument().getName());
}
}
}
}
/** Removes all documents for a given role.
*
* @param role The role object.
*/
public void removeRoleDocuments( Role role )
{
ProfileLocator locator = Profiler.createLocator();
locator.setRole(role);
StringBuffer buffer = new StringBuffer();
buffer.append(PATH_ROLE);
String name = role.getName();
if (null != name && name.length() > 0)
{
buffer.append(File.separator)
.append(name);
}
else
return; // don't delete the entire role directories
String path = buffer.toString();
File base = this.rootDir;
File file = new File(base, path);
try
{
name = file.getCanonicalPath();
}
catch (IOException e)
{
logger.error("PSMLManager: unable to resolve file path for "+ file);
}
synchronized (documents)
{
DirectoryUtils.rmdir(name);
Iterator it = documents.getIterator();
while (it.hasNext())
{
FileCacheEntry entry = (FileCacheEntry)it.next();
if (null == entry)
{
continue;
}
Profile profile = (Profile)entry.getDocument();
if (null == profile)
{
continue;
}
Role pRole = profile.getRole();
if (null != pRole && pRole.getName().equals(role.getName()))
{
documents.remove(profile.getDocument().getName());
}
}
}
}
/** Removes all documents for a given group.
*
* @param group The group object.
*/
public void removeGroupDocuments( Group group )
{
ProfileLocator locator = Profiler.createLocator();
locator.setGroup(group);
StringBuffer buffer = new StringBuffer();
buffer.append(PATH_GROUP);
String name = group.getName();
if (null != name && name.length() > 0)
{
buffer.append(File.separator)
.append(name);
}
else
return; // don't delete the entire group directories
String path = buffer.toString();
File base = this.rootDir;
File file = new File(base, path);
try
{
name = file.getCanonicalPath();
}
catch (IOException e)
{
logger.error("PSMLManager: unable to resolve file path for "+ file);
}
synchronized (documents)
{
DirectoryUtils.rmdir(name);
Iterator it = documents.getIterator();
while (it.hasNext())
{
FileCacheEntry entry = (FileCacheEntry)it.next();
if (null == entry)
{
continue;
}
Profile profile = (Profile)entry.getDocument();
if (null == profile)
{
continue;
}
Group pGroup = profile.getGroup();
if (null != pGroup && pGroup.getName().equals(group.getName()))
{
documents.remove(profile.getDocument().getName());
}
}
}
}
/**
* Maps a ProfileLocator to a file.
*
* @param locator The profile locator describing the PSML resource to be found.
* @return the String path of the file.
*/
protected String mapLocatorToFile(ProfileLocator locator)
{
StringBuffer path = new StringBuffer();
// move the base dir is either user or role is specified
Role role = locator.getRole();
Group group = locator.getGroup();
JetspeedUser user = locator.getUser();
if (user != null)
{
path.append(PATH_USER);
String name = user.getUserName();
if (null != name && name.length() > 0)
{
path.append(File.separator)
.append(name);
}
}
else if (group != null)
{
path.append(PATH_GROUP);
String name = group.getName();
if (null != name && name.length() > 0)
{
path.append(File.separator)
.append(name);
}
}
else if (null != role)
{
path.append(PATH_ROLE);
String name = role.getName();
if (null != name && name.length() > 0)
{
path.append(File.separator)
.append(name);
}
}
// Media
if (null != locator.getMediaType())
{
path.append(File.separator)
.append(locator.getMediaType());
}
// Language
if (null != locator.getLanguage() && (! locator.getLanguage().equals("-1")))
{
path.append(File.separator)
.append(locator.getLanguage());
}
// Country
if (null != locator.getCountry() && (! locator.getCountry().equals("-1")))
{
path.append(File.separator)
.append(locator.getCountry());
}
// Resource Name
if (null != locator.getName())
{
if (!(locator.getName().endsWith(CastorPsmlManagerService.DEFAULT_EXT)))
{
path.append(File.separator)
.append(locator.getName()).append(CastorPsmlManagerService.DEFAULT_EXT);
}
else
{
path.append(File.separator)
.append(locator.getName());
}
}
else
{
path.append(File.separator)
.append(DEFAULT_RESOURCE);
}
return path.toString();
}
protected static int STATE_INIT = 0;
protected static int STATE_BASE = 1;
protected static int STATE_NAME = 2;
protected static int STATE_MEDIA = 3;
protected static int STATE_LANGUAGE = 4;
protected static int STATE_COUNTRY = 5;
/** Query for a collection of profiles given a profile locator criteria.
*
* @param locator The profile locator criteria.
*/
public Iterator query( QueryLocator locator )
{
List list = new LinkedList();
Role role = locator.getRole();
Group group = locator.getGroup();
JetspeedUser user = locator.getUser();
// search thru anonymous directories?
int qm = locator.getQueryMode();
if ((qm & QueryLocator.QUERY_USER) == QueryLocator.QUERY_USER)
{
Profile profile = createProfile();
StringBuffer path = new StringBuffer();
path.append(PATH_USER);
String name = null;
int state = STATE_INIT;
if (null != user)
{
name = user.getUserName();
profile.setUser( user );
if (null != name)
{
path.append(File.separator).append(name);
state = STATE_BASE;
}
}
File base = this.rootDir;
File file = new File(base, path.toString());
String absPath = file.getAbsolutePath();
QueryState qs = new QueryState( QUERY_BY_USER,
profile,
locator,
list,
name,
state);
subQuery(qs, absPath);
}
if ((qm & QueryLocator.QUERY_ROLE) == QueryLocator.QUERY_ROLE)
{
Profile profile = createProfile();
StringBuffer path = new StringBuffer();
path.append(PATH_ROLE);
String name = null;
int state = STATE_INIT;
if (null != role)
{
name = role.getName();
profile.setRole( role );
if (null != name)
{
path.append(File.separator).append(name);
state = STATE_BASE;
}
}
File base = this.rootDir;
File file = new File(base, path.toString());
String absPath = null;
try
{
absPath = file.getCanonicalPath();
}
catch (IOException e)
{
logger.error("PSMLManager: unable to resolve file path for "+ file);
}
QueryState qs = new QueryState( QUERY_BY_ROLE,
profile,
locator,
list,
name,
state);
subQuery(qs, absPath);
}
if ((qm & QueryLocator.QUERY_GROUP) == QueryLocator.QUERY_GROUP)
{
Profile profile = createProfile();
StringBuffer path = new StringBuffer();
path.append(PATH_GROUP);
String name = null;
int state = STATE_INIT;
if (null != group)
{
name = group.getName();
profile.setGroup( group );
if (null != name)
{
path.append(File.separator).append(name);
state = STATE_BASE;
}
}
File base = this.rootDir;
File file = new File(base, path.toString());
String absPath = null;
try
{
absPath = file.getCanonicalPath();
}
catch (IOException e)
{
logger.error("PSMLManager: unable to resolve file path for "+ file);
}
QueryState qs = new QueryState( QUERY_BY_GROUP,
profile,
locator,
list,
name,
state);
subQuery(qs, absPath);
}
return list.iterator();
}
/** Create a profile based on import flag.
*
*/
protected Profile createProfile()
{
if (importFlag)
return new ImportProfile(this, this.consumer);
else
return Profiler.createProfile();
}
protected Profile createProfile(ProfileLocator locator)
{
if (importFlag)
return new ImportProfile(this, this.consumer, locator);
else
return Profiler.createProfile(locator);
}
/** Query for a collection of profiles given a profile locator criteria.
* This method should be used when importing or exporting profiles between services.
*
* @param locator The profile locator criteria.
* @return The count of profiles exported.
*/
public int export(PsmlManagerService consumer, QueryLocator locator)
{
importFlag = true;
Iterator profiles = null;
int count = 0;
try
{
this.consumer = consumer;
profiles = query(locator);
while (profiles.hasNext() )
{
Profile profile = (Profile)profiles.next();
//dumpProfile(profile);
try
{
consumer.createDocument(profile);
count++;
}
catch (Exception ex)
{
try
{
consumer.store(profile);
count++;
}
catch (Exception e)
{
logger.error("PSMLManager: Failed to export profiles to DB: " + profile, ex );
}
}
}
}
catch(Exception e)
{
e.printStackTrace();
logger.error("PSMLManager: Failed to export profiles to DB: " , e );
}
finally
{
importFlag = false;
}
return count;
}
/** Query for a collection of profiles given a profile locator criteria.
* To specify 'all' - use '*' in the criteria
*
* @param locator The profile locator criteria.
*/
protected void subQuery(QueryState qs, String path)
{
File file = new File(path);
if (file.isFile())
{
try
{
String filename = file.getName();
if (!filename.endsWith(this.ext))
return;
Profile clone = (Profile)qs.profile.clone();
clone.setName(filename);
qs.list.add( clone );
}
catch (Exception e)
{
logger.error("PSMLManager: Failed to clone profile: " + path + " : " + e, e);
}
}
else if (file.isDirectory())
{
String dirName = file.getName();
qs.state++;
// filter out based on name, mediatype, language, country
if (qs.state == STATE_NAME)
{
if (null != qs.name)
{
if (!dirName.equals(qs.name))
return;
}
try
{
if (QUERY_BY_USER == qs.queryBy)
{
JetspeedUser user = (JetspeedUser)qs.profile.getUser();
if (null == user)
{
user = JetspeedUserFactory.getInstance();
user.setUserName(file.getName());
qs.profile.setUser(user);
qs.clearName = true;
}
}
else if (QUERY_BY_ROLE == qs.queryBy)
{
Role role = qs.profile.getRole();
if (null == role)
{
role = JetspeedRoleFactory.getInstance();
role.setName(file.getName());
qs.profile.setRole(role);
qs.clearName = true;
}
}
else if (QUERY_BY_GROUP == qs.queryBy)
{
Group group = qs.profile.getGroup();
if (null == group)
{
group = JetspeedGroupFactory.getInstance();
group.setName(file.getName());
qs.profile.setGroup(group);
qs.clearName = true;
}
}
}
catch (Exception e)
{}
}
else if (qs.state == STATE_MEDIA)
{
String media = qs.locator.getMediaType();
if (null != media)
{
if (!dirName.equals(media))
return;
}
else
{
qs.profile.setMediaType(dirName);
qs.clearMedia = true;
}
}
else if (qs.state == STATE_LANGUAGE)
{
String language = qs.locator.getLanguage();
if (null != language)
{
if (!dirName.equals(language))
return;
}
else
{
qs.profile.setLanguage(dirName);
qs.clearLanguage = true;
}
}
else if (qs.state == STATE_COUNTRY)
{
String country = qs.locator.getCountry();
if (null != country)
{
if (!dirName.equals(country))
return;
}
else
{
qs.profile.setCountry(dirName);
qs.clearCountry = true;
}
}
if (!path.endsWith(File.separator))
path += File.separator;
String files[] = file.list();
// Process all files recursivly
for(int ix = 0; files != null && ix < files.length; ix++)
{
subQuery(qs, path + files[ix]);
}
// clear state
if (qs.state == STATE_NAME && true == qs.clearName)
{
if (QUERY_BY_USER == qs.queryBy)
qs.profile.setUser(null);
else if (QUERY_BY_ROLE == qs.queryBy)
qs.profile.setRole(null);
else if (QUERY_BY_GROUP == qs.queryBy)
qs.profile.setGroup(null);
qs.clearName = false;
}
else if (qs.state == STATE_MEDIA && true == qs.clearMedia)
{
qs.profile.setMediaType(null);
qs.clearMedia = false;
}
else if (qs.state == STATE_LANGUAGE && true == qs.clearLanguage)
{
qs.profile.setLanguage(null);
qs.clearLanguage = false;
}
else if (qs.state == STATE_COUNTRY && true == qs.clearCountry)
{
qs.profile.setCountry(null);
qs.clearCountry = false;
}
qs.state--;
}
}
static int QUERY_BY_USER = 0;
static int QUERY_BY_ROLE = 1;
static int QUERY_BY_GROUP = 2;
protected class QueryState
{
QueryState( int queryBy,
Profile profile,
ProfileLocator locator,
List list,
String name,
int state)
{
this.queryBy = queryBy;
this.profile = profile;
this.locator = locator;
this.list = list;
this.name = name;
this.state = state;
}
protected int queryBy;
protected Profile profile;
protected ProfileLocator locator;
protected List list;
protected String name;
protected int state;
protected boolean clearName = false;
protected boolean clearMedia = false;
protected boolean clearLanguage = false;
protected boolean clearCountry = false;
}
protected void testCases()
{
try
{
QueryLocator locator = new QueryLocator( QueryLocator.QUERY_USER );
Iterator x1 = query( locator );
dump( x1 );
QueryLocator locator2 = new QueryLocator( QueryLocator.QUERY_USER );
locator2.setUser( JetspeedSecurity.getUser("turbine") );
Iterator x2 = query( locator2 );
dump( x2 );
QueryLocator locator4 = new QueryLocator( QueryLocator.QUERY_GROUP );
// locator4.setGroup( JetspeedSecurity.getGroup("apache") );
Iterator x4 = query( locator4 );
dump( x4 );
}
catch (Exception e)
{
System.out.println( "Exception in Debug:" + e);
}
}
protected void dump( Iterator it )
{
System.out.println("===============================================");
while (it.hasNext() )
{
Profile profile = (Profile)it.next();
dumpProfile(profile);
}
System.out.println("===============================================");
}
protected void dumpProfile(Profile profile)
{
JetspeedUser user = profile.getUser();
Group group = profile.getGroup();
Role role = profile.getRole();
if (profile.getAnonymous() == true)
System.out.println("ANON USER");
System.out.println("RESOURCE = " + profile.getName());
if (null != user)
System.out.println("USER = " + user.getUserName() );
if (null != group)
System.out.println("GROUP = " + group.getName() );
if (null != role)
System.out.println("ROLE = " + role.getName() );
System.out.println("MEDIA TYPE = " + profile.getMediaType());
System.out.println("LANGUAGE = " + profile.getLanguage());
System.out.println("COUNTRY = " + profile.getCountry());
PSMLDocument doc = profile.getDocument();
if (null == doc)
System.out.println("Document is null");
else
{
if (null == profile.getName())
System.out.println("profile name is null");
else
System.out.println("Doc.name=" + profile.getName());
}
System.out.println("----------------------");
}
/**
* Refresh event, called when the entry is being refreshed from file system.
*
* @param entry the entry being refreshed.
*/
public void refresh(FileCacheEntry entry)
{
if (logger.isInfoEnabled())
{
logger.info("CastorPsmlManager: Entry is refreshing: " + entry.getFile().getPath());
}
Profile profile = (Profile) entry.getDocument();
String path = null;
if (profile != null)
{
try
{
path = entry.getFile().getCanonicalPath();
profile.setDocument(loadDocument(path));
}
catch(java.io.IOException e)
{
logger.error("CastorPsmlManager: Failed to refresh document "+path);
}
}
}
/**
* Evict event, called when the entry is being evicted out of the cache
*
* @param entry the entry being refreshed.
*/
public void evict(FileCacheEntry entry)
{
System.out.println("entry is evicting: " + entry.getFile().getName());
}
}