/* $Id: FilenetImpl.java 988245 2010-08-23 18:39:35Z kwright $ */ /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.manifoldcf.crawler.common.filenet; import java.rmi.*; import java.rmi.server.UnicastRemoteObject; import java.net.MalformedURLException; import java.net.URL; import java.util.*; import java.io.*; import com.filenet.api.core.*; import com.filenet.api.util.UserContext; import com.filenet.api.collection.*; import com.filenet.api.meta.*; import com.filenet.api.admin.*; import com.filenet.api.query.*; import com.filenet.api.util.*; import com.filenet.api.exception.*; import com.filenet.api.security.*; import com.filenet.api.constants.*; import com.filenet.api.property.*; /** This class abstracts away from the filenet methods necessary to "do things" that * the crawler or authority needs to be done with the Filenet repository. */ public class FilenetImpl extends UnicastRemoteObject implements IFilenet { public static final String _rcsid = "@(#)$Id: FilenetImpl.java 988245 2010-08-23 18:39:35Z kwright $"; //Web service login module name private static final String PARAM_LOGIN_MODULE = "FileNetP8WSI"; //Top level document class name private static final String PARAM_ROOT_DOC_CLASSNAME = "Document"; private String userID = null; private String password = null; private String serverWsiURI=null; private String fnDomainString=null; private String objectStoreName=null; private Connection conn = null; private com.filenet.api.core.ObjectStore os = null; private Domain fnDomain = null; private UserContext uc =null; /** Instantiate */ public FilenetImpl() throws RemoteException { super(0,new RMILocalClientSocketFactory(),new RMILocalSocketFactory()); } /** Create a session. *@param userID is the userID to use to establish the session. *@param password is the password to use to establish the session. *@param objectStore is the object store to use to establish the session. *@param serverWSIURI is the URI to use to get to the server's web services. */ public void createSession(String userID, String password, String domain, String objectStore, String serverWSIURI) throws FilenetException, RemoteException { this.userID = userID; this.password = password; this.fnDomainString = domain; this.serverWsiURI = serverWSIURI; this.objectStoreName = objectStore; // Now, set up the connection try { conn = Factory.Connection.getConnection(serverWsiURI); setConnectionCredentials(); //uc = UserContext.get(); //uc.setLocale(null); //uc.pushSubject(UserContext.createSubject(conn, userName, password, PARAM_LOGIN_MODULE)); fnDomain = Factory.Domain.fetchInstance(conn,fnDomainString, null); if (fnDomain == null) throw new FilenetException("Could not locate FileNet domain '"+fnDomain+"'"); os = Factory.ObjectStore.fetchInstance(fnDomain, objectStoreName, null); if (os == null) throw new FilenetException("Could not locate FileNet objectstore '"+objectStoreName+"'"); } catch(EngineRuntimeException e) { Throwable e2 = e.getCause(); ExceptionCode code = e.getExceptionCode(); if (code.equals(ExceptionCode.TRANSPORT_WSI_NETWORK_ERROR)) throw new FilenetException("Transport error: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_SERVICEINTERRUPTION); if (code.equals(ExceptionCode.SECURITY_WSI_NO_LOGIN_MODULES_SUCCEEDED)) throw new FilenetException("Login failure: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_BADCREDENTIALS); if (code.equals(ExceptionCode.API_INVALID_URI)) throw new FilenetException("Invalid URI error connecting to FileNet: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():"")+" This probably means your connection parameters are incorrect.",FilenetException.TYPE_BADCONNECTIONPARAMS); throw new FilenetException("Runtime exception connecting to FileNet: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():"")); } catch(Exception e) { throw new FilenetException("Exception connecting to FileNet: "+e.getMessage()); } } /** Delete a session. */ public void destroySession() throws FilenetException, RemoteException { userID = null; password = null; serverWsiURI = null; fnDomainString = null; objectStoreName = null; fnDomain = null; os = null; conn = null; } /** Check if there is a working connection. */ public void checkConnection() throws FilenetException, RemoteException { // Establishing a working session is enough to test connectivity } /** Get the set of folder names that are children of the specified folder path. */ public String[] getChildFolders(String[] parentFolderPath) throws FilenetException, RemoteException { setConnectionCredentials(); // Start at root. Folder currentFolder = os.get_RootFolder(); // Work our way down through the path. If the path turns out to be invalid, // we return null. int i = 0; while (i < parentFolderPath.length) { // For each path segment, find the matching child folder FolderSet folderSet = currentFolder.get_SubFolders(); currentFolder = null; Iterator fldrIter = folderSet.iterator(); while (fldrIter.hasNext()) { Folder folder = (Folder)fldrIter.next(); if (folder.get_FolderName().equals(parentFolderPath[i])) { currentFolder = folder; break; } } // Found no folder object with the correct name; the setup must have changed. if (currentFolder == null) return null; i++; } // We've located the correct parent folder object. Construct a list of children to return. ArrayList rval = new ArrayList(); FolderSet children = currentFolder.get_SubFolders(); Iterator childFolderIterator = children.iterator(); while (childFolderIterator.hasNext()) { Folder child = (Folder)childFolderIterator.next(); rval.add(child.get_FolderName()); } String[] rvalArray = new String[rval.size()]; rval.toArray(rvalArray); return rvalArray; } /** Get the set of available document classes. */ public DocumentClassDefinition[] getDocumentClassesDetails() throws FilenetException, RemoteException { DocumentClassDefinition[] oDocClasses=null; setConnectionCredentials(); ArrayList docClasses = getFNDocClasses(PARAM_ROOT_DOC_CLASSNAME); docClasses.add(new DocumentClassDefinition(PARAM_ROOT_DOC_CLASSNAME,PARAM_ROOT_DOC_CLASSNAME)); oDocClasses = new DocumentClassDefinition[docClasses.size()]; docClasses.toArray((DocumentClassDefinition[]) oDocClasses); return oDocClasses; } /** Get the set of available metadata fields per document class */ public MetadataFieldDefinition[] getDocumentClassMetadataFieldsDetails(String documentClassName) throws FilenetException, RemoteException { MetadataFieldDefinition[] oProps =null; ArrayList propDescs = new ArrayList(); PropertyDescriptionList pdescs=null; setConnectionCredentials(); int i=0; try { PropertyFilter pf = new PropertyFilter(); pf.addIncludeType(0, null, Boolean.TRUE, FilteredPropertyType.ANY, null); ClassDescription classDesc = (ClassDescription)Factory.ClassDescription.fetchInstance(os, documentClassName, pf); if (classDesc != null) { pdescs = classDesc.get_PropertyDescriptions(); PropertyDescription propDesc = null; Iterator iter = pdescs.iterator(); while (iter.hasNext()) { propDesc = (PropertyDescription) iter.next(); MetadataFieldDefinition mdf = new MetadataFieldDefinition(propDesc.get_DisplayName(),propDesc.get_SymbolicName()); propDescs.add(mdf); } } } catch (EngineRuntimeException e) { Throwable e2 = e.getCause(); throw new FilenetException("Runtime exception getting document class properties: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():"")); } catch(Exception e) { throw new FilenetException("FileNet exception getting document class properties: "+e.getMessage()); } oProps = new MetadataFieldDefinition[propDescs.size()]; propDescs.toArray(oProps); return oProps; } /** Execute a sql statement against FileNet and return the matching object id's */ public String[] getMatchingObjectIds(String sql) throws RemoteException, FilenetException { setConnectionCredentials(); HashMap docIds = new HashMap(); SearchSQL sqlObject = new SearchSQL(); sqlObject.setQueryString(sql); // System.out.println("Sql string is: "+sql); SearchScope searchScope = new SearchScope(os); // Uses fetchRows to test the SQL statement. try { // System.out.println("Fetching rows"); RepositoryRowSet rowSet = searchScope.fetchRows(sqlObject, null, null, new Boolean(true)); Iterator iter = rowSet.iterator(); while (iter.hasNext()) { // System.out.println("Found a row"); RepositoryRow row = (RepositoryRow) iter.next(); String docId = row.getProperties().get("Id").getIdValue().toString(); docIds.put(docId,docId); } } catch (EngineRuntimeException e) { Throwable e2 = e.getCause(); ExceptionCode code = e.getExceptionCode(); if (code.equals(ExceptionCode.TRANSPORT_WSI_NETWORK_ERROR)) throw new FilenetException("Transport error: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_SERVICEINTERRUPTION); if (code.equals(ExceptionCode.SECURITY_WSI_NO_LOGIN_MODULES_SUCCEEDED)) throw new FilenetException("Login failure: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_BADCREDENTIALS); if (code.equals(ExceptionCode.E_ACCESS_DENIED)) throw new FilenetException("Access denied getting document information: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_NOTALLOWED); throw new FilenetException("Runtime exception getting matching object ids: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():"")); } catch(Exception e) { throw new FilenetException("Query failed: '" + sql + "':" + e.getMessage(),e); } String[] rval = new String[docIds.size()]; Iterator iter = docIds.keySet().iterator(); int i = 0; while (iter.hasNext()) { String docId = (String)iter.next(); rval[i] = docId; i++; } return rval; } /** Get the document content information given an object id. Will return null if the version id is not a current document version id. */ public Integer getDocumentContentCount(String docId) throws RemoteException, FilenetException { setConnectionCredentials(); try { com.filenet.api.core.Document doc = Factory.Document.fetchInstance(os, docId, null); if (doc == null) return null; ContentElementList elements = doc.get_ContentElements(); int count = elements.size(); return new Integer(count); } catch (EngineRuntimeException e) { Throwable e2 = e.getCause(); ExceptionCode code = e.getExceptionCode(); if (code.equals(ExceptionCode.TRANSPORT_WSI_NETWORK_ERROR)) throw new FilenetException("Transport error: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_SERVICEINTERRUPTION); if (code.equals(ExceptionCode.SECURITY_WSI_NO_LOGIN_MODULES_SUCCEEDED)) throw new FilenetException("Login failure: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_BADCREDENTIALS); if (code.equals(ExceptionCode.E_ACCESS_DENIED)) throw new FilenetException("Access denied getting content information: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_NOTALLOWED); if (code.equals(ExceptionCode.API_NO_CONTENT_ELEMENTS)) return new Integer(0); if (code.equals(ExceptionCode.E_OBJECT_NOT_FOUND)) return null; throw new FilenetException("Runtime exception getting content information: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():"")); } catch(Exception e) { throw new FilenetException("Content count request failed: '" + docId + "':" + e.getMessage(),e); } } /** Get document information for a given filenet document. Will return null if the version id is not a current document version id. * The metadataFields hashmap is keyed by document class, and contains as a value either Boolean(true) (meaning "all"), or a String[] that has the * list of fields desired. */ public FileInfo getDocumentInformation(String docId, Map<String,Object> metadataFields) throws FilenetException, RemoteException { //System.out.println("Looking for document information on "+docId); setConnectionCredentials(); try { com.filenet.api.core.Document doc = Factory.Document.fetchInstance(os, docId, null); if (doc == null) { //System.out.println(" For "+docId+", null object return"); return null; } if(!(doc.get_IsCurrentVersion().booleanValue())) { //System.out.println(" For "+docId+",isCurrent() is false"); return null; } //else // System.out.println("For "+docId+" isCurrent() is true"); String docClass = doc.getClassName(); FileInfo rval = new FileInfo(docClass); //System.out.println("Got class name for "+docId); Object metadataObject = metadataFields.get(docClass); if (metadataObject != null && metadataObject instanceof Boolean) { // "All metadata" com.filenet.api.property.Properties props = doc.getProperties(); Iterator iter = props.iterator(); while (iter.hasNext()) { com.filenet.api.property.Property prop = (com.filenet.api.property.Property)iter.next(); String sPropName = prop.getPropertyName(); Object objPropVal = prop.getObjectValue(); if (objPropVal != null) rval.addMetadataValue(sPropName, objPropVal.toString()); } } else if (metadataObject != null) { String[] fields = (String[])metadataObject; for (int j=0; j < fields.length; j++) { String sPropName = fields[j]; try { //System.out.println("Getting properties for "+docId); Object objPropVal = doc.getProperties().getObjectValue(sPropName); if (objPropVal != null) rval.addMetadataValue(sPropName,objPropVal.toString()); } catch (Exception e) { // Is this what happens when you ask for a property that doesn't exist? Ask - MHL } } } else { // It's a kind of document we didn't want return null; } //System.out.println("Getting permissions for "+docId); AccessPermissionList apl = doc.get_Permissions(); //System.out.println("Got permissions for "+docId); Iterator iter = apl.iterator(); while (iter.hasNext()) { AccessPermission ap = (AccessPermission)iter.next(); AccessType at = ap.get_AccessType(); int atval = at.getValue(); int am = ap.get_AccessMask().intValue(); int tmp = AccessLevel.VIEW_AS_INT; if ((am & tmp) == tmp && (atval==AccessType.ALLOW_AS_INT || atval==AccessType.DENY_AS_INT)) { String gname = ap.get_GranteeName(); // System.out.println("Docid "+docId+" has view access for "+gname); if (!gname.equals("#AUTHENTICATED-USERS")) { //System.out.println("Getting user "+gname); SecurityPrincipalType gtype = ap.get_GranteeType(); if (gtype.getValue() == SecurityPrincipalType.USER_AS_INT) { User usr = Factory.User.fetchInstance(conn, gname, null); if (usr != null) { String sid = usr.get_Id(); if (atval == AccessType.ALLOW_AS_INT) rval.addAclValue(sid); else if (atval == AccessType.DENY_AS_INT) rval.addDenyAclValue(sid); } } else { Group grp = Factory.Group.fetchInstance(conn, gname, null); if (grp != null) { String sid = grp.get_Id(); if (atval == AccessType.ALLOW_AS_INT) rval.addAclValue(sid); else if (atval == AccessType.DENY_AS_INT) rval.addDenyAclValue(sid); } } } else { if (atval == AccessType.ALLOW_AS_INT) // Still trying to verify that this SID means the right thing in this context rval.addAclValue("S-1-1-0"); else if (atval == AccessType.DENY_AS_INT) rval.addDenyAclValue("S-1-1-0"); } } // else // System.out.println("Docid "+docId+" has access level "+Integer.toString(am)+" with type "+Integer.toString(atval)); } // System.out.println("DocId "+docId+" has "+Integer.toString(rval.getAclCount())+" acls"); return rval; } catch (EngineRuntimeException e) { Throwable e2 = e.getCause(); ExceptionCode code = e.getExceptionCode(); if (code.equals(ExceptionCode.E_OBJECT_NOT_FOUND)) { //System.out.println(" For "+docId+", OBJECT_NOT_FOUND exception"); return null; } if (code.equals(ExceptionCode.TRANSPORT_WSI_NETWORK_ERROR)) throw new FilenetException("Transport error: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_SERVICEINTERRUPTION); if (code.equals(ExceptionCode.SECURITY_WSI_NO_LOGIN_MODULES_SUCCEEDED)) throw new FilenetException("Login failure: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_BADCREDENTIALS); if (code.equals(ExceptionCode.E_ACCESS_DENIED)) throw new FilenetException("Access denied getting document information: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_NOTALLOWED); throw new FilenetException("Runtime exception getting document information: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():"")); } catch(Exception e) { throw new FilenetException("Get document information failed:" + e.getMessage(),e); } } /** Get document contents */ public void getDocumentContents(String docId, int elementNumber, String tempFileName) throws FilenetException, RemoteException { setConnectionCredentials(); try { com.filenet.api.core.Document doc = Factory.Document.fetchInstance(os, docId, null); if (doc != null) { ContentElementList elements = doc.get_ContentElements(); Iterator iter = elements.iterator(); // There are multiple documents per "document version" possible in filenet. ContentTransfer element = null; int i = 0; while ( iter.hasNext()) { element = (ContentTransfer)iter.next(); if (i == elementNumber) break; i++; } if (element == null) throw new FilenetException("Could not locate element "+Integer.toString(elementNumber)+" in document '"+docId+"'"); File f = new File(tempFileName); InputStream is = element.accessContentStream(); try { // Copy the document to the temporary file so described, and return OutputStream os = new FileOutputStream(f); try { byte[] byteBuffer = new byte[65536]; while (true) { int amt = is.read(byteBuffer); if (amt == -1) break; os.write(byteBuffer,0,amt); } } finally { os.close(); } } catch (IOException e) { f.delete(); throw new FilenetException("Could not read file from FileNet for document '"+docId+"': "+e.getMessage(),e); } finally { try { is.close(); } catch (IOException e) { // Do nothing } } } else throw new FilenetException("Unknown file: '"+docId+"'"); } catch (EngineRuntimeException e) { Throwable e2 = e.getCause(); ExceptionCode code = e.getExceptionCode(); if (code.equals(ExceptionCode.E_OBJECT_NOT_FOUND)) throw new FilenetException("File not found: '"+docId+"'"); if (code.equals(ExceptionCode.TRANSPORT_WSI_NETWORK_ERROR)) throw new FilenetException("Transport error: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_SERVICEINTERRUPTION); if (code.equals(ExceptionCode.SECURITY_WSI_NO_LOGIN_MODULES_SUCCEEDED)) throw new FilenetException("Login failure: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_BADCREDENTIALS); if (code.equals(ExceptionCode.E_ACCESS_DENIED)) throw new FilenetException("Access denied getting document contents: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():""),FilenetException.TYPE_NOTALLOWED); throw new FilenetException("Runtime exception getting document contents: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():"")); } catch(Exception e) { throw new FilenetException("Get document contents failed:" + e.getMessage(),e); } } // Protected methods protected void setConnectionCredentials() { uc = UserContext.get(); //uc.setLocale(null); uc.pushSubject(UserContext.createSubject(conn, userID, password, PARAM_LOGIN_MODULE)); } protected ArrayList getFNDocClasses(String rootClass) throws FilenetException { ArrayList al = new ArrayList(); try { ClassDefinition classDef = Factory.ClassDefinition.fetchInstance(os, rootClass, null); ClassDefinitionSet cds = classDef.get_ImmediateSubclassDefinitions(); ClassDefinition clsDesc = null; Iterator iter = cds.iterator(); if (iter != null){ while (iter.hasNext()){ clsDesc = (ClassDefinition) iter.next(); al.addAll(getFNDocClasses(clsDesc.get_SymbolicName())); DocumentClassDefinition dc = new DocumentClassDefinition(clsDesc.get_DisplayName(),clsDesc.get_SymbolicName()); al.add(dc); } } } catch (EngineRuntimeException e) { Throwable e2 = e.getCause(); throw new FilenetException("Runtime exception getting FileNet class definition details: "+e.getMessage()+((e2!=null)?": "+e2.getMessage():"")); } catch(Exception e) { throw new FilenetException("Exception getting FileNet class definition details: "+e.getMessage()); } return al; } }