From 621d9e5c413e561293d7484b93882d985b3fe15f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Sat, 24 Mar 2012 02:27:47 -0500 Subject: Removed unnecessary pki folder. Previously the source code was located inside a pki folder. This folder was created during svn migration and is no longer needed. This folder has now been removed and the contents have been moved up one level. Ticket #131 --- .../netscape/cmscore/request/ARequestQueue.java | 1578 ++++++++++++++++++++ .../netscape/cmscore/request/ARequestRecord.java | 42 + .../cmscore/request/CertRequestConstants.java | 73 + .../netscape/cmscore/request/ExtDataHashtable.java | 78 + .../com/netscape/cmscore/request/RequestAttr.java | 61 + .../com/netscape/cmscore/request/RequestQueue.java | 709 +++++++++ .../netscape/cmscore/request/RequestRecord.java | 883 +++++++++++ .../cmscore/request/RequestRepository.java | 217 +++ .../netscape/cmscore/request/RequestSubsystem.java | 187 +++ .../src/com/netscape/cmscore/request/Schema.java | 50 + 10 files changed, 3878 insertions(+) create mode 100644 base/common/src/com/netscape/cmscore/request/ARequestQueue.java create mode 100644 base/common/src/com/netscape/cmscore/request/ARequestRecord.java create mode 100644 base/common/src/com/netscape/cmscore/request/CertRequestConstants.java create mode 100644 base/common/src/com/netscape/cmscore/request/ExtDataHashtable.java create mode 100644 base/common/src/com/netscape/cmscore/request/RequestAttr.java create mode 100644 base/common/src/com/netscape/cmscore/request/RequestQueue.java create mode 100644 base/common/src/com/netscape/cmscore/request/RequestRecord.java create mode 100644 base/common/src/com/netscape/cmscore/request/RequestRepository.java create mode 100644 base/common/src/com/netscape/cmscore/request/RequestSubsystem.java create mode 100644 base/common/src/com/netscape/cmscore/request/Schema.java (limited to 'base/common/src/com/netscape/cmscore/request') diff --git a/base/common/src/com/netscape/cmscore/request/ARequestQueue.java b/base/common/src/com/netscape/cmscore/request/ARequestQueue.java new file mode 100644 index 000000000..16db3985c --- /dev/null +++ b/base/common/src/com/netscape/cmscore/request/ARequestQueue.java @@ -0,0 +1,1578 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program 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; version 2 of the License. +// +// This program 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.request; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CRLException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.util.Arrays; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; +import java.util.Vector; + +import netscape.security.util.DerInputStream; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateSubjectName; +import netscape.security.x509.RevokedCertImpl; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509ExtensionException; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authentication.AuthToken; +import com.netscape.certsrv.authentication.IAuthToken; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IAttrSet; +import com.netscape.certsrv.base.SessionContext; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.AgentApprovals; +import com.netscape.certsrv.request.IEnrollmentRequest; +import com.netscape.certsrv.request.INotify; +import com.netscape.certsrv.request.IPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestList; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.IRequestScheduler; +import com.netscape.certsrv.request.IService; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestStatus; + +/** + * The ARequestQueue class is an abstract class that implements + * most portions of the IRequestQueue interface. This includes + * the state engine as defined for processing IRequest objects. + *

+ * !Put state machine description here! + *

+ * This class defines several abstract protected functions that need to be defined by the concrete implementation. In + * particular, this class does not implement the operations for storing requests persistantly. + *

+ * This class also provides several accessor functions for setting fields in the IRequest object. These functions are + * provided as an aid to saving and restoring the state in the database. + *

+ * This class also implements the locking operations specified by the IRequestQueue interface. + *

+ * + * @author thayes + * @version $Revision$ $Date$ + */ +public abstract class ARequestQueue + implements IRequestQueue { + + /** + * global request version for tracking request changes. + */ + public final static String REQUEST_VERSION = "1.0.0"; + + /** + * Create a new (unique) RequestId. (abstract) + *

+ * This method must be implemented by the specialized class to generate a new id from data in the persistant store. + * This id is used to create a new request object. + *

+ * + * @return + * a new RequestId object. + * @exception EBaseException + * indicates that creation of the new id could not be completed. + * @see RequestId + */ + protected abstract RequestId newRequestId() + throws EBaseException; + + /** + * Read a request from the persistant store. (abstract) + *

+ * This function is called to create the in-memory version of a request object. + *

+ * The implementation of this object can use the createRequest member function to create a new instance of an + * IRequest, and use the setRequestStatus, setCreationTime and setModificationTime functions to set those values. + *

+ * + * @param id + * the id of the request to read. + * @return + * a new IRequest object. null is returned if the object cannot + * be located. + * @exception EBaseException + * TODO: this is not implemented yet + * @see #createRequest + * @see #setRequestStatus + * @see #setModificationTime + * @see #setCreationTime + */ + protected abstract IRequest readRequest(RequestId id); + + /** + * Add the request to the store. (abstract) + *

+ * This function is called when a new request immediately after creating a new request. + *

+ * + * @param request + * the request to add. + * @exception EBaseException + * TODO: this is not implemented yet + */ + protected abstract void addRequest(IRequest request) throws EBaseException; + + /** + * Modify the request in the store. (abstract) + *

+ * Update the persistant copy of this request with the current values in the object. + *

+ * Currently there are no hints for what has changed, so the entire request should be updated. + *

+ * + * @param request + * @exception EBaseException + * TODO: this is not implemented yet + */ + protected abstract void modifyRequest(IRequest request); + + /** + * Get complete list of RequestId values found i this + * queue. + *

+ * This method can form the basis for creating other types of search/list operations (although there are probably + * more efficient ways of doing this. ARequestQueue implements default versions of some of the searching by using + * this method as a basis. + *

+ * TODO: return IRequestList -or- just use listRequests as the basic engine. + *

+ * + * @return + * an Enumeration that generates RequestId objects. + */ + abstract protected Enumeration getRawList(); + + /** + * protected access for setting the current state of a request. + *

+ * + * @param request + * The request to be modified. + * @param status + * The new value for the request status. + */ + protected final void setRequestStatus(IRequest request, RequestStatus status) { + Request r = (Request) request; + + r.setRequestStatus(status); + } + + /** + * protected access for setting the modification time of a request. + *

+ * + * @param request + * The request to be modified. + * @param date + * The new value for the time. + */ + protected final void setModificationTime(IRequest request, Date date) { + Request r = (Request) request; + + r.mModificationTime = date; + } + + /** + * protected access for setting the creation time of a request. + *

+ * + * @param request + * The request to be modified. + * @param date + * The new value for the time. + */ + protected final void setCreationTime(IRequest request, Date date) { + Request r = (Request) request; + + r.mCreationTime = date; + } + + /** + * protected access for creating a new Request object + *

+ * + * @param id + * The identifier for the new request + * @return + * A new request object. The caller should fill in other data + * values from the datastore. + */ + protected final IRequest createRequest(RequestId id, String requestType) { + Request r; + + /* + * Determine the specialized class to create for this type + * + * TODO: this set of classes is an example only. The real set + * needs to be determined and implemented. + */ + if (requestType != null && requestType.equals("enrollment")) { + r = new EnrollmentRequest(id); + } else { + r = new Request(id); + } + + return r; + } + + /** + * Implements IRequestQueue.newRequest + *

+ * + * @see IRequestQueue#newRequest + */ + public IRequest newRequest(String requestType) + throws EBaseException { + if (requestType == null) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_REQUEST_TYPE", "null")); + } + RequestId rId = newRequestId(); + IRequest r = createRequest(rId, requestType); + + // Commented out the lock call because unlock is never called. + // mTable.lock(rId); + + // TODO: move this to the first update. This will require + // some state information to track the current state. + r.setRequestType(requestType); + r.setExtData(IRequest.REQ_VERSION, REQUEST_VERSION); + + // NOT_UPDATED mean request is in memory and has + // not been serialized to database yet. An add + // operation is required to serialize a NOT_UPDATED + // request. + r.setExtData("dbStatus", "NOT_UPDATED"); + // addRequest(r); + + // expose requestId to policy so that it can be + // used with predicate + r.setExtData("requestId", rId.toString()); + + return r; + } + + /** + * Implements IRequestQueue.cloneRequest + *

+ * + * @see IRequestQueue#cloneRequest + */ + public IRequest cloneRequest(IRequest r) + throws EBaseException { + // 1. check for valid state. (Are any invalid ?) + RequestStatus rs = r.getRequestStatus(); + + if (rs == RequestStatus.BEGIN) + throw new EBaseException("Invalid Status"); + + // 2. create new request + String reqType = r.getRequestType(); + IRequest clone = newRequest(reqType); + + // 3. copy all attributes of original request to clone and modify. + // source id (from remote authority) is not copied. + // TODO: set the original request id to some place in the request. + clone.copyContents(r); + // NOT_UPDATED mean request is in memory and has + // not been serialized to database yet. An add + // operation is required to serialize a NOT_UPDATED + // request. + clone.setExtData("dbStatus", "NOT_UPDATED"); + + return clone; + } + + /** + * Implements IRequestQueue.findRequest + *

+ * + * @see IRequestQueue#findRequest + */ + public IRequest findRequest(RequestId id) + throws EBaseException { + IRequest r; + + // mTable.lock(id); + + r = readRequest(id); + + // if (r == null) mTable.unlock(id); + + return r; + } + + private IRequestScheduler mRequestScheduler = null; + + public void setRequestScheduler(IRequestScheduler scheduler) { + mRequestScheduler = scheduler; + } + + public IRequestScheduler getRequestScheduler() { + return mRequestScheduler; + } + + /** + * Implements IRequestQueue.processRequest + *

+ * + * @see IRequestQueue#processRequest + */ + public final void processRequest(IRequest r) + throws EBaseException { + + // #610553 Thread Scheduler + IRequestScheduler scheduler = getRequestScheduler(); + + if (scheduler != null) { + scheduler.requestIn(r); + } + + try { + // 1. Check for valid state + RequestStatus rs = r.getRequestStatus(); + + if (rs != RequestStatus.BEGIN) + throw new EBaseException("Invalid Status"); + + stateEngine(r); + } finally { + if (scheduler != null) { + scheduler.requestOut(r); + } + } + } + + /** + * Implements IRequestQueue.markRequestPending + *

+ * + * @see IRequestQueue#markRequestPending + */ + public final void markRequestPending(IRequest r) + throws EBaseException { + // 1. Check for valid state + RequestStatus rs = r.getRequestStatus(); + + if (rs != RequestStatus.BEGIN) + throw new EBaseException("Invalid Status"); + + // 2. Change the request state. This method of making + // a request PENDING does NOT invoke the PENDING notifiers. + // To change this, just call stateEngine at the completion of this + // routine. + setRequestStatus(r, RequestStatus.PENDING); + + updateRequest(r); + stateEngine(r); + } + + /** + * Implements IRequestQueue.cloneAndMarkPending + *

+ * + * @see IRequestQueue#cloneAndMarkPending + */ + public IRequest cloneAndMarkPending(IRequest r) + throws EBaseException { + IRequest clone = cloneRequest(r); + + markRequestPending(clone); + return clone; + } + + /** + * Implements IRequestQueue.approveRequest + *

+ * + * @see IRequestQueue#approveRequest + */ + public final void approveRequest(IRequest r) + throws EBaseException { + // 1. Check for valid state + RequestStatus rs = r.getRequestStatus(); + + if (rs != RequestStatus.PENDING) + throw new EBaseException("Invalid Status"); + + AgentApprovals aas = AgentApprovals.fromStringVector( + r.getExtDataInStringVector(AgentApprovals.class.getName())); + if (aas == null) { + aas = new AgentApprovals(); + } + + // Record agent who did this + String agentName = getUserIdentity(); + + if (agentName == null) + throw new EBaseException("Missing agent information"); + + aas.addApproval(agentName); + r.setExtData(AgentApprovals.class.getName(), (Vector) aas.toStringVector()); + + PolicyResult pr = mPolicy.apply(r); + + if (pr == PolicyResult.ACCEPTED) { + setRequestStatus(r, RequestStatus.APPROVED); + } else if (pr == PolicyResult.DEFERRED || + pr == PolicyResult.REJECTED) { + } + + // Always update. The policy code may have made changes to the + // request that we want to keep. + updateRequest(r); + + stateEngine(r); + } + + /** + * Implements IRequestQueue.rejectRequest + *

+ * + * @see IRequestQueue#rejectRequest + */ + public final void rejectRequest(IRequest r) + throws EBaseException { + // 1. Check for valid state + RequestStatus rs = r.getRequestStatus(); + + if (rs != RequestStatus.PENDING) + throw new EBaseException("Invalid Status"); + + // 2. Change state + setRequestStatus(r, RequestStatus.REJECTED); + updateRequest(r); + + // 3. Continue processing + stateEngine(r); // does nothing + } + + /** + * Implments IRequestQueue.cancelRequest + *

+ * + * @see IRequestQueue#cancelRequest + */ + public final void cancelRequest(IRequest r) + throws EBaseException { + setRequestStatus(r, RequestStatus.CANCELED); + updateRequest(r); + + stateEngine(r); + + return; + } + + /** + * caller must lock request and release request + */ + public final void markAsServiced(IRequest r) { + setRequestStatus(r, RequestStatus.COMPLETE); + updateRequest(r); + + if (mNotify != null) + mNotify.notify(r); + + return; + } + + /** + * Implements IRequestQueue.listRequests + *

+ * Should be overridden by the specialized class if a more efficient method is available for implementing this + * operation. + *

+ * + * @see IRequestQueue#listRequests + */ + public IRequestList listRequests() { + return new RequestList(getRawList()); + } + + /** + * Implements IRequestQueue.listRequestsByStatus + *

+ * Should be overridden by the specialized class if a more efficient method is available for implementing this + * operation. + *

+ * + * @see IRequestQueue#listRequestsByStatus + */ + public IRequestList listRequestsByStatus(RequestStatus s) { + return new RequestListByStatus(getRawList(), s, this); + } + + /** + * Implements IRequestQueue.releaseRequest + *

+ * + * @see IRequestQueue#releaseRequest + */ + public final void releaseRequest(IRequest request) { + // mTable.unlock(request.getRequestId()); + } + + public void updateRequest(IRequest r) { + ((Request) r).mModificationTime = CMS.getCurrentDate(); + + String name = getUserIdentity(); + + if (name != null) + r.setExtData(IRequest.UPDATED_BY, name); + + // TODO: use a state flag to determine whether to call + // addRequest or modifyRequest (see newRequest as well) + modifyRequest(r); + } + + // PRIVATE functions + + private final void stateEngine(IRequest r) + throws EBaseException { + boolean complete = false; + + while (!complete) { + RequestStatus rs = r.getRequestStatus(); + + if (rs == RequestStatus.BEGIN) { + PolicyResult pr = PolicyResult.ACCEPTED; + + if (mPolicy != null) + pr = mPolicy.apply(r); + + if (pr == PolicyResult.ACCEPTED) { + setRequestStatus(r, RequestStatus.APPROVED); + } else if (pr == PolicyResult.DEFERRED) { + setRequestStatus(r, RequestStatus.PENDING); + } else { + setRequestStatus(r, RequestStatus.REJECTED); + } + + // if policy accepts the request, the request + // will be processed right away. So speed up + // the request processing, we do not want to + // have too many db operation. + if (pr != PolicyResult.ACCEPTED) { + updateRequest(r); + } + } else if (rs == RequestStatus.PENDING) { + if (mPendingNotify != null) + mPendingNotify.notify(r); + + complete = true; + } else if (rs == RequestStatus.APPROVED) { + boolean svcComplete; + + svcComplete = mService.serviceRequest(r); + + // Completed requests call the notifier and are done. Others + // wait for the serviceComplete call. + if (svcComplete) { + setRequestStatus(r, RequestStatus.COMPLETE); + } else { + setRequestStatus(r, RequestStatus.SVC_PENDING); + } + + updateRequest(r); + } else if (rs == RequestStatus.SVC_PENDING) { + complete = true; + } else if (rs == RequestStatus.CANCELED) { + if (mNotify != null) + mNotify.notify(r); + + complete = true; + } else if (rs == RequestStatus.REJECTED) { + if (mNotify != null) + mNotify.notify(r); + + complete = true; + } else if (rs == RequestStatus.COMPLETE) { + if (mNotify != null) + mNotify.notify(r); + + complete = true; + } + } + } + + /** + * log a change in the request status + */ + protected void logChange(IRequest request) { + // write the queue name and request id + // write who changed it + // write what change (which state change) was made + // - new (processRequest) + // - approve + // - reject + + // Ordering + // - make change in memory + // - log change and result + // - update record + } + + /** + * get the identity of the current user + */ + protected String getUserIdentity() { + // Record agent who did this + SessionContext s = SessionContext.getContext(); + String name = (String) s.get(SessionContext.USER_ID); + + return name; + } + + /** + * New non-blocking recover method. + */ + public void recover() { + if (CMS.isRunningMode()) { + RecoverThread t = new RecoverThread(this); + + t.start(); + } + } + + /** + * recover from a crash. Resends all requests that are in + * the APPROVED state. + */ + public void recoverWillBlock() { + // Get a list of all requests that are APPROVED + IRequestList list = listRequestsByStatus(RequestStatus.APPROVED); + + while (list != null && list.hasMoreElements()) { + RequestId rid = list.nextRequestId(); + IRequest request; + + try { + request = findRequest(rid); + + //if (request == null) log_error + + // Recheck the status - should be the same!! + if (request.getRequestStatus() == RequestStatus.APPROVED) { + stateEngine(request); + } + + releaseRequest(request); + } catch (EBaseException e) { + // log + } + } + } + + public INotify getPendingNotify() { + return mPendingNotify; + } + + // Constructor + protected ARequestQueue(IPolicy policy, IService service, INotify notify, + INotify pendingNotify) { + mPolicy = policy; + mService = service; + mNotify = notify; + mPendingNotify = pendingNotify; + + mLogger = CMS.getLogger(); + } + + // Instance variables + // RequestIDTable mTable = new RequestIDTable(); + + IPolicy mPolicy; + IService mService; + INotify mNotify; + INotify mPendingNotify; + + protected ILogger mLogger; +} + +// +// Table of RequestId values that are currently in use by some thread. +// The fact that the request is in this table constitutes a lock +// on the value. +// +/* + class RequestIDTable { + public synchronized void lock(RequestId id) { + while (true) { + if (mHashtable.put(id, id) == null) + break; + + try { + wait(); + } catch (InterruptedException e) { + }; + } + } + + public synchronized void unlock(RequestId id) { + mHashtable.remove(id); + + notifyAll(); + } + + // instance variables + Hashtable mHashtable = new Hashtable(); + } + */ + +// +// Request - implementation of the IRequest interface. This +// version is returned by ARequestQueue (and its derivatives) +// +class Request + implements IRequest { + // IRequest.getRequestId + public RequestId getRequestId() { + return mRequestId; + } + + // IRequest.getRequestStatus + public RequestStatus getRequestStatus() { + return mRequestStatus; + } + + // Obsolete + public void setRequestStatus(RequestStatus s) { + mRequestStatus = s; + // expose request status so that we can do predicate upon it + setExtData(IRequest.REQ_STATUS, s.toString()); + } + + public boolean isSuccess() { + Integer result = getExtDataInInteger(IRequest.RESULT); + + if (result != null && result.equals(IRequest.RES_SUCCESS)) + return true; + else + return false; + } + + public String getError(Locale locale) { + return getExtDataInString(IRequest.ERROR); + } + + // IRequest.getSourceId + public String getSourceId() { + return mSourceId; + } + + // IRequest.setSourceId + public void setSourceId(String id) { + mSourceId = id; + } + + // IRequest.getRequestOwner + public String getRequestOwner() { + return mOwner; + } + + // IRequest.setRequestOwner + public void setRequestOwner(String id) { + mOwner = id; + } + + // IRequest.getRequestType + public String getRequestType() { + return mRequestType; + } + + // IRequest.setRequestType + public void setRequestType(String type) { + mRequestType = type; + setExtData(IRequest.REQ_TYPE, type); + } + + // IRequest.getRequestVersion + public String getRequestVersion() { + return getExtDataInString(IRequest.REQ_VERSION); + } + + // IRequest.getCreationTime + public Date getCreationTime() { + return mCreationTime; + } + + public String getContext() { + return mContext; + } + + public void setContext(String ctx) { + mContext = ctx; + } + + // IRequest.getModificationTime + public Date getModificationTime() { + return mModificationTime; + } + + /** + * this isn't that efficient but will do for now. + */ + public void copyContents(IRequest req) { + Enumeration e = req.getExtDataKeys(); + while (e.hasMoreElements()) { + String key = (String) e.nextElement(); + if (!key.equals(IRequest.ISSUED_CERTS) && + !key.equals(IRequest.ERRORS) && + !key.equals(IRequest.REMOTE_REQID)) { + if (req.isSimpleExtDataValue(key)) { + setExtData(key, req.getExtDataInString(key)); + } else { + setExtData(key, req.getExtDataInHashtable(key)); + } + } + } + } + + /** + * This function used to check that the keys obeyed LDAP attribute name + * syntax rules. Keys are being encoded now, so it is changed to just + * filter out null and empty string keys. + * + * @param key The key to check + * @return false if invalid + */ + protected boolean isValidExtDataKey(String key) { + return key != null && + (!key.equals("")); + } + + protected boolean isValidExtDataHashtableValue(Hashtable hash) { + if (hash == null) { + return false; + } + Enumeration keys = hash.keys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + if (!((key instanceof String) && isValidExtDataKey((String) key))) { + return false; + } + /* + * TODO should the Value type be String? + */ + Object value = hash.get(key); + if (!(value instanceof String)) { + return false; + } + } + + return true; + } + + public boolean setExtData(String key, String value) { + if (!isValidExtDataKey(key)) { + return false; + } + if (value == null) { + return false; + } + + mExtData.put(key, value); + return true; + } + + public boolean setExtData(String key, Hashtable value) { + if (!(isValidExtDataKey(key) && isValidExtDataHashtableValue(value))) { + return false; + } + + mExtData.put(key, new ExtDataHashtable(value)); + return true; + } + + public boolean isSimpleExtDataValue(String key) { + return (mExtData.get(key) instanceof String); + } + + public String getExtDataInString(String key) { + Object value = mExtData.get(key); + if (value == null) { + return null; + } + if (!(value instanceof String)) { + return null; + } + return (String) value; + } + + @SuppressWarnings("unchecked") + public Hashtable getExtDataInHashtable(String key) { + Object value = mExtData.get(key); + if (value == null) { + return null; + } + if (!(value instanceof Hashtable)) { + return null; + } + return new ExtDataHashtable((Hashtable) value); + } + + public Enumeration getExtDataKeys() { + return mExtData.keys(); + } + + public void deleteExtData(String type) { + mExtData.remove(type); + } + + public boolean setExtData(String key, String subkey, String value) { + if (!(isValidExtDataKey(key) && isValidExtDataKey(subkey))) { + return false; + } + if (isSimpleExtDataValue(key)) { + return false; + } + if (value == null) { + return false; + } + + @SuppressWarnings("unchecked") + Hashtable existingValue = (Hashtable) mExtData.get(key); + if (existingValue == null) { + existingValue = new ExtDataHashtable(); + mExtData.put(key, existingValue); + } + existingValue.put(subkey, value); + return true; + } + + public String getExtDataInString(String key, String subkey) { + Hashtable value = getExtDataInHashtable(key); + if (value == null) { + return null; + } + return value.get(subkey); + } + + public boolean setExtData(String key, Integer value) { + if (value == null) { + return false; + } + return setExtData(key, value.toString()); + } + + public Integer getExtDataInInteger(String key) { + String strVal = getExtDataInString(key); + if (strVal == null) { + return null; + } + try { + return Integer.valueOf(strVal); + } catch (NumberFormatException e) { + return null; + } + } + + public boolean setExtData(String key, Integer[] data) { + if (data == null) { + return false; + } + String[] stringArray = new String[data.length]; + for (int index = 0; index < data.length; index++) { + stringArray[index] = data[index].toString(); + } + return setExtData(key, stringArray); + } + + public Integer[] getExtDataInIntegerArray(String key) { + String[] stringArray = getExtDataInStringArray(key); + if (stringArray == null) { + return null; + } + Integer[] intArray = new Integer[stringArray.length]; + for (int index = 0; index < stringArray.length; index++) { + try { + intArray[index] = new Integer(stringArray[index]); + } catch (NumberFormatException e) { + return null; + } + } + return intArray; + } + + public boolean setExtData(String key, BigInteger value) { + if (value == null) { + return false; + } + return setExtData(key, value.toString()); + } + + public BigInteger getExtDataInBigInteger(String key) { + String strVal = getExtDataInString(key); + if (strVal == null) { + return null; + } + try { + return new BigInteger(strVal); + } catch (NumberFormatException e) { + return null; + } + } + + public boolean setExtData(String key, BigInteger[] data) { + if (data == null) { + return false; + } + String[] stringArray = new String[data.length]; + for (int index = 0; index < data.length; index++) { + stringArray[index] = data[index].toString(); + } + return setExtData(key, stringArray); + } + + public BigInteger[] getExtDataInBigIntegerArray(String key) { + String[] stringArray = getExtDataInStringArray(key); + if (stringArray == null) { + return null; + } + BigInteger[] intArray = new BigInteger[stringArray.length]; + for (int index = 0; index < stringArray.length; index++) { + try { + intArray[index] = new BigInteger(stringArray[index]); + } catch (NumberFormatException e) { + return null; + } + } + return intArray; + } + + public boolean setExtData(String key, Throwable e) { + if (e == null) { + return false; + } + return setExtData(key, e.toString()); + } + + public boolean setExtData(String key, byte[] data) { + if (data == null) { + return false; + } + return setExtData(key, CMS.BtoA(data)); + } + + public byte[] getExtDataInByteArray(String key) { + String value = getExtDataInString(key); + if (value != null) { + return CMS.AtoB(value); + } + return null; + } + + public boolean setExtData(String key, X509CertImpl data) { + if (data == null) { + return false; + } + try { + return setExtData(key, data.getEncoded()); + } catch (CertificateEncodingException e) { + return false; + } + } + + public X509CertImpl getExtDataInCert(String key) { + byte[] data = getExtDataInByteArray(key); + if (data != null) { + try { + return new X509CertImpl(data); + } catch (CertificateException e) { + return null; + } + } + return null; + } + + public boolean setExtData(String key, X509CertImpl[] data) { + if (data == null) { + return false; + } + String[] stringArray = new String[data.length]; + for (int index = 0; index < data.length; index++) { + try { + stringArray[index] = CMS.BtoA(data[index].getEncoded()); + } catch (CertificateEncodingException e) { + return false; + } + } + return setExtData(key, stringArray); + } + + public X509CertImpl[] getExtDataInCertArray(String key) { + String[] stringArray = getExtDataInStringArray(key); + if (stringArray == null) { + return null; + } + X509CertImpl[] certArray = new X509CertImpl[stringArray.length]; + for (int index = 0; index < stringArray.length; index++) { + try { + certArray[index] = new X509CertImpl(CMS.AtoB(stringArray[index])); + } catch (CertificateException e) { + return null; + } + } + return certArray; + } + + public boolean setExtData(String key, X509CertInfo data) { + if (data == null) { + return false; + } + try { + return setExtData(key, data.getEncodedInfo(true)); + } catch (CertificateEncodingException e) { + return false; + } + } + + public X509CertInfo getExtDataInCertInfo(String key) { + byte[] data = getExtDataInByteArray(key); + if (data != null) { + try { + return new X509CertInfo(data); + } catch (CertificateException e) { + return null; + } + } + return null; + } + + public boolean setExtData(String key, X509CertInfo[] data) { + if (data == null) { + return false; + } + String[] stringArray = new String[data.length]; + for (int index = 0; index < data.length; index++) { + try { + stringArray[index] = CMS.BtoA(data[index].getEncodedInfo(true)); + } catch (CertificateEncodingException e) { + return false; + } + } + return setExtData(key, stringArray); + } + + public X509CertInfo[] getExtDataInCertInfoArray(String key) { + String[] stringArray = getExtDataInStringArray(key); + if (stringArray == null) { + return null; + } + X509CertInfo[] certArray = new X509CertInfo[stringArray.length]; + for (int index = 0; index < stringArray.length; index++) { + try { + certArray[index] = new X509CertInfo(CMS.AtoB(stringArray[index])); + } catch (CertificateException e) { + return null; + } + } + return certArray; + } + + public boolean setExtData(String key, RevokedCertImpl[] data) { + if (data == null) { + return false; + } + String[] stringArray = new String[data.length]; + for (int index = 0; index < data.length; index++) { + try { + stringArray[index] = CMS.BtoA(data[index].getEncoded()); + } catch (CRLException e) { + return false; + } + } + return setExtData(key, stringArray); + } + + public RevokedCertImpl[] getExtDataInRevokedCertArray(String key) { + String[] stringArray = getExtDataInStringArray(key); + if (stringArray == null) { + return null; + } + RevokedCertImpl[] certArray = new RevokedCertImpl[stringArray.length]; + for (int index = 0; index < stringArray.length; index++) { + try { + certArray[index] = new RevokedCertImpl(CMS.AtoB(stringArray[index])); + } catch (CRLException e) { + return null; + } catch (X509ExtensionException e) { + return null; + } + } + return certArray; + } + + public boolean setExtData(String key, Vector stringVector) { + String[] stringArray; + if (stringVector == null) { + return false; + } + try { + stringArray = (String[]) stringVector.toArray(new String[0]); + } catch (ArrayStoreException e) { + return false; + } + return setExtData(key, stringArray); + } + + public Vector getExtDataInStringVector(String key) { + String[] stringArray = getExtDataInStringArray(key); + if (stringArray == null) { + return null; + } + return new Vector(Arrays.asList(stringArray)); + } + + public boolean getExtDataInBoolean(String key, boolean defVal) { + String val = getExtDataInString(key); + if (val == null) + return defVal; + return val.equalsIgnoreCase("true") || val.equalsIgnoreCase("ON"); + } + + public boolean getExtDataInBoolean(String prefix, String type, boolean defVal) { + String val = getExtDataInString(prefix, type); + if (val == null) + return defVal; + return val.equalsIgnoreCase("true") || val.equalsIgnoreCase("ON"); + } + + public boolean setExtData(String key, IAuthToken data) { + if (data == null) { + return false; + } + Hashtable hash = new Hashtable(); + Enumeration keys = data.getElements(); + while (keys.hasMoreElements()) { + try { + String authKey = keys.nextElement(); + hash.put(authKey, data.getInString(authKey)); + } catch (ClassCastException e) { + return false; + } + } + return setExtData(key, hash); + } + + public IAuthToken getExtDataInAuthToken(String key) { + Hashtable hash = getExtDataInHashtable(key); + if (hash == null) { + return null; + } + AuthToken authToken = new AuthToken(null); + Enumeration keys = hash.keys(); + while (keys.hasMoreElements()) { + try { + String hashKey = (String) keys.nextElement(); + authToken.set(hashKey, (String) hash.get(hashKey)); + } catch (ClassCastException e) { + return null; + } + } + return authToken; + } + + public boolean setExtData(String key, CertificateExtensions data) { + if (data == null) { + return false; + } + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + try { + data.encode(byteStream); + } catch (CertificateException e) { + return false; + } catch (IOException e) { + return false; + } + return setExtData(key, byteStream.toByteArray()); + } + + public CertificateExtensions getExtDataInCertExts(String key) { + CertificateExtensions exts = null; + byte[] extensionsData = getExtDataInByteArray(key); + if (extensionsData != null) { + exts = new CertificateExtensions(); + try { + exts.decodeEx(new ByteArrayInputStream(extensionsData)); + // exts.decode() does not work when the CertExts size is 0 + // exts.decode(new ByteArrayInputStream(extensionsData)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return exts; + } + + public boolean setExtData(String key, CertificateSubjectName data) { + if (data == null) { + return false; + } + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + try { + data.encode(byteStream); + } catch (IOException e) { + return false; + } + return setExtData(key, byteStream.toByteArray()); + } + + public CertificateSubjectName getExtDataInCertSubjectName(String key) { + CertificateSubjectName name = null; + byte[] nameData = getExtDataInByteArray(key); + if (nameData != null) { + try { + // You must use DerInputStream + // using ByteArrayInputStream fails + name = new CertificateSubjectName( + new DerInputStream(nameData)); + } catch (IOException e) { + return null; + } + } + return name; + } + + public boolean setExtData(String key, String[] values) { + if (values == null) { + return false; + } + Hashtable hashValue = new Hashtable(); + for (int index = 0; index < values.length; index++) { + hashValue.put(Integer.toString(index), values[index]); + } + return setExtData(key, hashValue); + } + + public String[] getExtDataInStringArray(String key) { + int index; + + Hashtable hashValue = getExtDataInHashtable(key); + if (hashValue == null) { + String s = getExtDataInString(key); + if (s == null) { + return null; + } else { + String[] sa = { s }; + return sa; + } + } + Set arrayKeys = hashValue.keySet(); + Vector listValue = new Vector(arrayKeys.size()); + for (Iterator iter = arrayKeys.iterator(); iter.hasNext();) { + String arrayKey = iter.next(); + try { + index = Integer.parseInt(arrayKey); + } catch (NumberFormatException e) { + return null; + } + if (listValue.size() < (index + 1)) { + listValue.setSize(index + 1); + } + listValue.set(index, + hashValue.get(arrayKey)); + } + return listValue.toArray(new String[0]); + } + + public IAttrSet asIAttrSet() { + return new RequestIAttrSetWrapper(this); + } + + Request(RequestId id) { + mRequestId = id; + setRequestStatus(RequestStatus.BEGIN); + } + + // instance variables + protected RequestId mRequestId; + protected RequestStatus mRequestStatus; + protected String mSourceId; + protected String mSource; + protected String mOwner; + protected String mRequestType; + protected String mContext; // string for now. + protected ExtDataHashtable mExtData = new ExtDataHashtable(); + + Date mCreationTime = CMS.getCurrentDate(); + Date mModificationTime = CMS.getCurrentDate(); +} + +class RequestIAttrSetWrapper implements IAttrSet { + /** + * + */ + private static final long serialVersionUID = 8231914824991772682L; + IRequest mRequest; + + public RequestIAttrSetWrapper(IRequest request) { + mRequest = request; + } + + public void set(String name, Object obj) throws EBaseException { + try { + mRequest.setExtData(name, (String) obj); + } catch (ClassCastException e) { + throw new EBaseException(e.toString()); + } + } + + public Object get(String name) throws EBaseException { + return mRequest.getExtDataInString(name); + } + + public void delete(String name) throws EBaseException { + mRequest.deleteExtData(name); + } + + public Enumeration getElements() { + return mRequest.getExtDataKeys(); + } +} + +/** + * Example of a specialized request class. + */ +class EnrollmentRequest + extends Request + implements IEnrollmentRequest { + EnrollmentRequest(RequestId id) { + super(id); + } +} + +class RequestListByStatus + implements IRequestList { + public boolean hasMoreElements() { + return (mNext != null); + } + + public Object nextRequest() { + return null; + } + + public IRequest nextRequestObject() { + return null; + } + + public RequestId nextElement() { + RequestId next = mNext; + + update(); + + return next; + } + + public RequestId nextRequestId() { + RequestId next = mNext; + + update(); + + return next; + } + + public RequestListByStatus(Enumeration e, RequestStatus s, IRequestQueue q) { + mEnumeration = e; + mStatus = s; + mQueue = q; + + update(); + } + + protected void update() { + RequestId rId; + + mNext = null; + + while (mNext == null) { + if (!mEnumeration.hasMoreElements()) + break; + + rId = mEnumeration.nextElement(); + + try { + IRequest r = mQueue.findRequest(rId); + + if (r.getRequestStatus() == mStatus) + mNext = rId; + + mQueue.releaseRequest(r); + } catch (Exception e) { + } + } + } + + protected RequestStatus mStatus; + protected IRequestQueue mQueue; + protected Enumeration mEnumeration; + protected RequestId mNext; +} + +class RequestList + implements IRequestList { + public boolean hasMoreElements() { + return mEnumeration.hasMoreElements(); + } + + public RequestId nextElement() { + return mEnumeration.nextElement(); + } + + public RequestId nextRequestId() { + return (RequestId) mEnumeration.nextElement(); + } + + public Object nextRequest() { + return null; + } + + public IRequest nextRequestObject() { + return null; + } + + public RequestList(Enumeration e) { + mEnumeration = e; + } + + protected Enumeration mEnumeration; +} + +class RecoverThread extends Thread { + private ARequestQueue mQ = null; + + public RecoverThread(ARequestQueue q) { + mQ = q; + setName("RequestRecoverThread"); + } + + public void run() { + mQ.recoverWillBlock(); + } +} diff --git a/base/common/src/com/netscape/cmscore/request/ARequestRecord.java b/base/common/src/com/netscape/cmscore/request/ARequestRecord.java new file mode 100644 index 000000000..e23d4007c --- /dev/null +++ b/base/common/src/com/netscape/cmscore/request/ARequestRecord.java @@ -0,0 +1,42 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program 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; version 2 of the License. +// +// This program 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.request; + +import java.util.Date; +import java.util.Hashtable; + +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestStatus; + +/** + * The low level (attributes only) version of the database + * record object. This exists so that RecordAttr methods can use + * this type definition, + * + * RequestRecord refers both to this class and to RecordAttr objects. + */ +class ARequestRecord { + RequestId mRequestId; + RequestStatus mRequestState; + Date mCreateTime; + Date mModifyTime; + String mSourceId; + String mOwner; + String mRequestType; + Hashtable mExtData; +}; diff --git a/base/common/src/com/netscape/cmscore/request/CertRequestConstants.java b/base/common/src/com/netscape/cmscore/request/CertRequestConstants.java new file mode 100644 index 000000000..eab41fcd5 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/request/CertRequestConstants.java @@ -0,0 +1,73 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program 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; version 2 of the License. +// +// This program 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.request; + +/** + * temporary location for cert request constants. + * XXX we really need to centralize all these but for now they are here + * as needed. + */ +public class CertRequestConstants { + // request types - these have string values. + // made to match policy constants. + public final static String GETCRL_REQUEST = "getCRL"; + public final static String GETCACHAIN_REQUEST = "getCAChain"; + public final static String GETREVOCATIONINFO_REQUEST = "getRevocationInfo"; + + public final static String REVOCATION_CHECK_CHALLENGE_REQUEST = "checkChallengePhrase"; + public final static String GETCERTS_FOR_CHALLENGE_REQUEST = "getCertsForChallenge"; + + // BigInteger Value and BigIntegerValue array. + public final static String SERIALNO = "serialNumber"; + public final static String SERIALNOS = "serialNumbers"; + + // int value. + public final static String REVOKE_REASON = "revokeReason"; + + // this has a string value. + public final static String HOLDINSTRCODE = "holdInstrCode"; + public final static String HOLDCALLISSUER = "holdCallIssuer"; + public final static String HOLDREJECT = "holdReject"; + + // this has a Date value. + public final static String INVALIDITYDATE = "InvalidityDate"; + + // this has a CRLExtensions value. + public final static String CRLEXTS = "CRLExts"; + + // this has a String value - it is either null or set. + public final static String DOGETCACHAIN = "doGetCAChain"; + + // this has a CertificateChain value. + public final static String CACERTCHAIN = "CACertChain"; + + // this has a CRL value. + public final static String CRL = "CRL"; + + // this has a X509CertImpl value. + public final static String CERTIFICATE = "certificate"; + + // this is an array of EBaseException for service errors when + // there's an error processing an array of something such as + // certs to renew, certs to revoke, etc. + public final static String SVCERRORS = "serviceErrors"; + + // crl update status after a revocation. + public final static String CRL_UPDATE_STATUS = "crlUpdateStatus"; + public final static String CRL_UPDATE_ERROR = "crlUpdateError"; +} diff --git a/base/common/src/com/netscape/cmscore/request/ExtDataHashtable.java b/base/common/src/com/netscape/cmscore/request/ExtDataHashtable.java new file mode 100644 index 000000000..86e6c0530 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/request/ExtDataHashtable.java @@ -0,0 +1,78 @@ +package com.netscape.cmscore.request; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * Subclass of Hashtable returned by IRequest.getExtDataInHashtable. Its + * purpose is to hide the fact that LDAP doesn't preserve the case of keys. + * It does this by lowercasing all keys used to access the Hashtable. + */ +public class ExtDataHashtable extends Hashtable { + + /** + * + */ + private static final long serialVersionUID = 8401134619951331450L; + + public ExtDataHashtable() { + super(); + } + + public ExtDataHashtable(int i) { + super(i); + } + + public ExtDataHashtable(int i, float v) { + super(i, v); + } + + public ExtDataHashtable(Map map) { + // the super constructor seems to call putAll, but I can't + // rely on that behaviour + super(); + putAll(map); + } + + public boolean containsKey(Object o) { + if (o instanceof String) { + String key = (String) o; + return super.containsKey(key.toLowerCase()); + } + return super.containsKey(o); + } + + public V get(Object o) { + if (o instanceof String) { + String key = (String) o; + return super.get(key.toLowerCase()); + } + return super.get(o); + } + + public V put(String oKey, V val) { + if (oKey instanceof String) { + String key = (String) oKey; + return super.put(key.toLowerCase(), val); + } + return super.put(oKey, val); + } + + public void putAll(Map map) { + Set keys = map.keySet(); + for (Iterator i = keys.iterator(); i.hasNext();) { + Object key = i.next(); + put((String) key, map.get(key)); + } + } + + public V remove(Object o) { + if (o instanceof String) { + String key = (String) o; + return super.remove(key.toLowerCase()); + } + return super.remove(o); + } +} diff --git a/base/common/src/com/netscape/cmscore/request/RequestAttr.java b/base/common/src/com/netscape/cmscore/request/RequestAttr.java new file mode 100644 index 000000000..25734c91e --- /dev/null +++ b/base/common/src/com/netscape/cmscore/request/RequestAttr.java @@ -0,0 +1,61 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program 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; version 2 of the License. +// +// This program 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.request; + +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.ldap.IRequestMod; + +/** + * The RequestAttr class defines the methods used + * to transfer data between the various representations of + * a request. The three forms are: + * 1) LDAPAttributes (and Modifications) + * 2) Database record IDBAttrSet + * 3) IRequest (Request) object + */ +abstract class RequestAttr { + + /** + * + */ + + abstract void set(ARequestRecord r, Object o); + + abstract Object get(ARequestRecord r); + + abstract void read(IRequestMod a, IRequest r, ARequestRecord rr); + + abstract void add(IRequest r, ARequestRecord rr); + + abstract void mod(ModificationSet mods, IRequest r); + + RequestAttr(String attrName, IDBAttrMapper mapper) { + mAttrName = attrName; + mMapper = mapper; + } + + protected void addmod(ModificationSet mods, Object o) { + mods.add(mAttrName, Modification.MOD_REPLACE, o); + } + + String mAttrName; + IDBAttrMapper mMapper; +} diff --git a/base/common/src/com/netscape/cmscore/request/RequestQueue.java b/base/common/src/com/netscape/cmscore/request/RequestQueue.java new file mode 100644 index 000000000..ef13d3c29 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/request/RequestQueue.java @@ -0,0 +1,709 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program 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; version 2 of the License. +// +// This program 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.request; + +import java.math.BigInteger; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSearchResults; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.IDBVirtualList; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.dbs.repository.IRepository; +import com.netscape.certsrv.request.INotify; +import com.netscape.certsrv.request.IPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestList; +import com.netscape.certsrv.request.IRequestRecord; +import com.netscape.certsrv.request.IRequestVirtualList; +import com.netscape.certsrv.request.IService; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.certsrv.request.ldap.IRequestMod; +import com.netscape.cmscore.dbs.DBSubsystem; +import com.netscape.cmscore.util.Debug; + +public class RequestQueue + extends ARequestQueue + implements IRequestMod { + // ARequestQueue.newRequestId + protected RequestId newRequestId() + throws EBaseException { + // get the next request Id + BigInteger next = mRepository.getNextSerialNumber(); + + RequestId rid = new RequestId(next); + + return rid; + } + + protected IRequest readRequest(RequestId id) { + RequestRecord record; + + // String name = Schema.LDAP_ATTR_REQUEST_ID + "=" + + String name = "cn" + "=" + + id + "," + mBaseDN; + + Object obj = null; + IDBSSession dbs = null; + + try { + dbs = mDB.createSession(); + obj = dbs.read(name); + } catch (EBaseException e) { + Debug.trace("Error: " + e); + Debug.printStackTrace(e); + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) + try { + dbs.close(); + } catch (EBaseException e) { + } + } + + // TODO Errors!!! + if (obj == null || !(obj instanceof RequestRecord)) + return null; + + record = (RequestRecord) obj; + + /* + setRequestStatus(r, record.mRequestState); + r.setSourceId(record.mSourceId); + r.setRequestOwner(record.mOwner); + record.storeAttrs(r, record.mRequestAttrs); + setModificationTime(r, record.mModifyTime); + setCreationTime(r, record.mCreateTime); + */ + return makeRequest(record); + } + + protected void addRequest(IRequest r) throws EBaseException { + // setup to call dbs.add(name, IAttrSet) + RequestRecord record = new RequestRecord(); + + record.add(r); + + // compute the name of the object + // String name = Schema.LDAP_ATTR_REQUEST_ID + "=" + + String name = "cn" + "=" + + record.mRequestId + "," + mBaseDN; + + IDBSSession dbs = null; + + try { + dbs = mDB.createSession(); + dbs.add(name, record); + } catch (EBaseException e) { + Debug.trace("Error: " + e); + Debug.printStackTrace(e); + throw e; + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) + try { + dbs.close(); + } catch (EBaseException e) { + } + } + } + + protected void modifyRequest(IRequest r) { + String dbStatus = r.getExtDataInString("dbStatus"); + + if (!dbStatus.equals("UPDATED")) { + try { + r.setExtData("dbStatus", "UPDATED"); + addRequest(r); + } catch (EBaseException e) { + System.out.println(e.toString()); + } + return; + } + + ModificationSet mods = new ModificationSet(); + + try { + RequestRecord.mod(mods, r); + } catch (EBaseException e) { + Debug.trace("Error: " + e); + Debug.printStackTrace(e); + } + + /* + // + mods.add(IRequestRecord.ATTR_REQUEST_STATE, + Modification.MOD_REPLACE, r.getRequestStatus()); + + mods.add(IRequestRecord.ATTR_SOURCE_ID, + Modification.MOD_REPLACE, r.getSourceId()); + + mods.add(IRequestRecord.ATTR_REQUEST_OWNER, + Modification.MOD_REPLACE, r.getRequestOwner()); + + mods.add(IRequestRecord.ATTR_MODIFY_TIME, + Modification.MOD_REPLACE, r.getModificationTime()); + + java.util.Hashtable ht = RequestRecord.loadAttrs(r); + mods.add(RequestRecord.ATTR_REQUEST_ATTRS, + Modification.MOD_REPLACE, ht); + */ + + // String name = Schema.LDAP_ATTR_REQUEST_ID + "=" + + String name = "cn" + "=" + + r.getRequestId() + "," + mBaseDN; + + IDBSSession dbs = null; + + try { + dbs = mDB.createSession(); + dbs.modify(name, mods); + } catch (EBaseException e) { + Debug.trace("Error: " + e); + Debug.printStackTrace(e); + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) + try { + dbs.close(); + } catch (EBaseException e) { + } + } + } + + IRequest makeRequest(RequestRecord record) { + IRequest r = createRequest(record.mRequestId, record.mRequestType); + + try { + // convert (copy) fields + record.read(this, r); + } catch (EBaseException e) { + Debug.trace("Error: " + e); + Debug.printStackTrace(e); + } + + return r; + } + + public void modRequestStatus(IRequest r, RequestStatus s) { + setRequestStatus(r, s); + } + + public void modCreationTime(IRequest r, Date d) { + setCreationTime(r, d); + } + + public void modModificationTime(IRequest r, Date d) { + setModificationTime(r, d); + } + + /** + * Resets serial number. + */ + public void resetSerialNumber(BigInteger serial) throws EBaseException { + mRepository.resetSerialNumber(serial); + } + + /** + * Removes all objects with this repository. + */ + public void removeAllObjects() throws EBaseException { + mRepository.removeAllObjects(); + } + + public BigInteger getLastRequestIdInRange(BigInteger reqId_low_bound, BigInteger reqId_upper_bound) { + CMS.debug("RequestQueue: getLastRequestId: low " + reqId_low_bound + " high " + reqId_upper_bound); + if (reqId_low_bound == null || reqId_upper_bound == null || reqId_low_bound.compareTo(reqId_upper_bound) >= 0) { + CMS.debug("RequestQueue: getLastRequestId: bad upper and lower bound range."); + return null; + } + + String filter = "(" + "requeststate" + "=*" + ")"; + + RequestId fromId = new RequestId(reqId_upper_bound); + + CMS.debug("RequestQueue: getLastRequestId: filter " + filter + " fromId " + fromId); + ListEnumeration recList = (ListEnumeration) getPagedRequestsByFilter(fromId, filter, 5 * -1, "requestId"); + + int size = recList.getSize(); + + CMS.debug("RequestQueue: getLastRequestId: size " + size); + + int ltSize = recList.getSizeBeforeJumpTo(); + + CMS.debug("RequestQueue: getSizeBeforeJumpTo: " + ltSize); + + if (size <= 0) { + CMS.debug("RequestQueue: getLastRequestId: request list is empty."); + + BigInteger ret = new BigInteger(reqId_low_bound.toString(10)); + + ret = ret.add(new BigInteger("-1")); + + CMS.debug("CertificateRepository:getLastCertRecordSerialNo: returning " + ret); + return ret; + } + + IRequest curRec = null; + + RequestId curId = null; + + String reqId = null; + + for (int i = 0; i < 5; i++) { + curRec = recList.getElementAt(i); + + if (curRec != null) { + + curId = curRec.getRequestId(); + + reqId = curId.toString(); + + CMS.debug("RequestQueue: curReqId: " + reqId); + + BigInteger curIdInt = new BigInteger(reqId); + + if (((curIdInt.compareTo(reqId_low_bound) == 0) || (curIdInt.compareTo(reqId_low_bound) == 1)) && + ((curIdInt.compareTo(reqId_upper_bound) == 0) || (curIdInt.compareTo(reqId_upper_bound) == -1))) { + CMS.debug("RequestQueue: getLastRequestId : returning value " + curIdInt); + return curIdInt; + } + + } + + } + + BigInteger ret = new BigInteger(reqId_low_bound.toString(10)); + + ret = ret.add(new BigInteger("-1")); + + CMS.debug("CertificateRepository:getLastCertRecordSerialNo: returning " + ret); + return ret; + + } + + /** + * Implements IRequestQueue.findRequestBySourceId + *

+ * + * @see com.netscape.certsrv.request.IRequestQueue#findRequestBySourceId + */ + public RequestId findRequestBySourceId(String id) { + IRequestList irl = findRequestsBySourceId(id); + + if (irl == null) + return null; + + return irl.nextRequestId(); + } + + /** + * Implements IRequestQueue.findRequestsBySourceId + *

+ * + * @see com.netscape.certsrv.request.IRequestQueue#findRequestsBySourceId + */ + public IRequestList findRequestsBySourceId(String id) { + IDBSearchResults results = null; + IDBSSession dbs = null; + + // Need only the requestid in the result of the search + // TODO: generic search returning RequestId + String filter = "(" + IRequestRecord.ATTR_SOURCE_ID + "=" + id + ")"; + + try { + dbs = mDB.createSession(); + results = dbs.search(mBaseDN, filter); + } catch (EBaseException e) { + Debug.trace("Error in Ldap Request searching code: " + e); + Debug.printStackTrace(e); + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) + try { + dbs.close(); + } catch (EBaseException e) { + } + } + + if (results == null || !results.hasMoreElements()) + return null; + + return new SearchEnumeration(this, results); + + } + + protected Enumeration getRawList() { + IDBSearchResults results = null; + IDBSSession dbs = null; + + try { + dbs = mDB.createSession(); + results = dbs.search(mBaseDN, "(requestId=*)"); + } catch (EBaseException e) { + Debug.trace("Error: " + e); + Debug.printStackTrace(e); + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) + try { + dbs.close(); + } catch (EBaseException e) { + } + } + + if (results == null) + return null; + + return new SearchEnumeration(this, results); + } + + /** + */ + public IRequestList listRequestsByFilter(String f) { + IDBSearchResults results = null; + IDBSSession dbs = null; + + try { + dbs = mDB.createSession(); + results = dbs.search(mBaseDN, f); + } catch (EBaseException e) { + Debug.trace("Error: " + e); + Debug.printStackTrace(e); + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) + try { + dbs.close(); + } catch (EBaseException e) { + } + } + + if (results == null) + return null; + + return new SearchEnumeration(this, results); + } + + /** + */ + public IRequestList listRequestsByFilter(String f, int maxSize) { + IDBSearchResults results = null; + IDBSSession dbs = null; + + try { + dbs = mDB.createSession(); + results = dbs.search(mBaseDN, f, maxSize); + } catch (EBaseException e) { + Debug.trace("Error: " + e); + Debug.printStackTrace(e); + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) + try { + dbs.close(); + } catch (EBaseException e) { + } + } + + if (results == null) + return null; + + return new SearchEnumeration(this, results); + } + + /** + */ + public IRequestList listRequestsByFilter(String f, int maxSize, int timeLimit) { + IDBSearchResults results = null; + IDBSSession dbs = null; + + try { + dbs = mDB.createSession(); + results = dbs.search(mBaseDN, f, maxSize, timeLimit); + } catch (EBaseException e) { + Debug.trace("Error: " + e); + Debug.printStackTrace(e); + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) + try { + dbs.close(); + } catch (EBaseException e) { + } + } + + if (results == null) + return null; + + return new SearchEnumeration(this, results); + } + + public IRequestList listRequestsByStatus(RequestStatus s) { + IDBSearchResults results = null; + IDBSSession dbs = null; + + try { + String f1; + String f2; + + f1 = "(" + IRequestRecord.ATTR_REQUEST_STATE + "=" + s + ")"; + f2 = "(" + IRequestRecord.ATTR_REQUEST_ID + "=*)"; + + f1 = "(&" + f1 + f2 + ")"; + + dbs = mDB.createSession(); + results = dbs.search(mBaseDN, f1); + } catch (EBaseException e) { + //System.err.println("Error: "+e); + //e.printStackTrace(); + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) + try { + dbs.close(); + } catch (EBaseException e) { + } + } + + if (results == null) + return null; + + return new SearchEnumeration(this, results); + } + + /* + * Implements IRequestQueue.getPagedRequests + */ + public IRequestVirtualList getPagedRequests(int pageSize) { + return getPagedRequestsByFilter("(requestId=*)", pageSize, "requestId"); + } + + /* + * Implements IRequestQueue.getPagedRequestsByFilter + */ + public IRequestVirtualList + getPagedRequestsByFilter(String filter, int pageSize, String sortKey) { + return getPagedRequestsByFilter(null, filter, pageSize, sortKey); + } + + public IRequestVirtualList + getPagedRequestsByFilter(RequestId from, String filter, int pageSize, + String sortKey) { + return getPagedRequestsByFilter(from, false, filter, pageSize, sortKey); + } + + public IRequestVirtualList + getPagedRequestsByFilter(RequestId from, boolean jumpToEnd, String filter, int pageSize, + String sortKey) { + IDBVirtualList results = null; + IDBSSession dbs = null; + + try { + dbs = mDB.createSession(); + } catch (EBaseException e) { + return null; + } + + try { + + if (from == null) { + results = dbs.createVirtualList(mBaseDN, filter, (String[]) null, + sortKey, pageSize); + } else { + int len = from.toString().length(); + String internalRequestId = null; + + if (jumpToEnd) { + internalRequestId = "99"; + } else { + if (len > 9) { + internalRequestId = Integer.toString(len) + from.toString(); + } else { + internalRequestId = "0" + Integer.toString(len) + + from.toString(); + } + } + + results = dbs.createVirtualList(mBaseDN, filter, (String[]) null, + internalRequestId, sortKey, pageSize); + } + } catch (EBaseException e) { + return null; + } finally { + try { + dbs.close(); + } catch (EBaseException e) { + } + } + + try { + results.setSortKey(sortKey); + } catch (EBaseException e) {//XXX + System.out.println(e.toString()); + return null; + } + + return new ListEnumeration(this, results); + } + + public RequestQueue(String name, int increment, IPolicy p, IService s, INotify n, + INotify pendingNotify) + throws EBaseException { + super(p, s, n, pendingNotify); + + mDB = DBSubsystem.getInstance(); + mBaseDN = "ou=" + name + ",ou=requests," + mDB.getBaseDN(); + + mRepository = new RequestRepository(name, increment, mDB, this); + + } + + /* + * list record attributes (debugging output) + */ + static void listRecordAttrs(String s, Hashtable h) { + System.err.println(s); + Enumeration e = h.keys(); + + while (e.hasMoreElements()) { + String name = e.nextElement(); + + System.err.println("Attr: " + name + " Value: " + h.get(name)); + } + } + + /* + * return request repository + */ + public IRepository getRequestRepository() { + return (IRepository) mRepository; + } + + public String getPublishingStatus() { + return mRepository.getPublishingStatus(); + } + + public void setPublishingStatus(String status) { + mRepository.setPublishingStatus(status); + } + + protected String mBaseDN; + protected IDBSubsystem mDB; + protected RequestRepository mRepository; +} + +class SearchEnumeration + implements IRequestList { + public RequestId nextRequestId() { + Object obj; + + obj = mResults.nextElement(); + + if (obj == null || !(obj instanceof RequestRecord)) + return null; + + RequestRecord r = (RequestRecord) obj; + + return r.mRequestId; + } + + public boolean hasMoreElements() { + return mResults.hasMoreElements(); + } + + public RequestId nextElement() { + return nextRequestId(); + } + + public SearchEnumeration(IDBSearchResults r) { + mResults = r; + } + + public SearchEnumeration(RequestQueue queue, IDBSearchResults r) { + mResults = r; + mQueue = queue; + } + + public Object nextRequest() { + Object obj; + + obj = mResults.nextElement(); + + if (obj == null || !(obj instanceof RequestRecord)) + return null; + + RequestRecord r = (RequestRecord) obj; + + return r; + } + + public IRequest nextRequestObject() { + RequestRecord record = (RequestRecord) nextRequest(); + if (record != null) + return mQueue.makeRequest(record); + return null; + } + + protected IDBSearchResults mResults; + protected RequestQueue mQueue; +} + +class ListEnumeration + implements IRequestVirtualList { + public IRequest getElementAt(int i) { + RequestRecord record = (RequestRecord) mList.getElementAt(i); + + if (record == null) + return null; + + return mQueue.makeRequest(record); + } + + public int getCurrentIndex() { + return mList.getCurrentIndex(); + } + + public int getSize() { + return mList.getSize(); + } + + public int getSizeBeforeJumpTo() { + return mList.getSizeBeforeJumpTo(); + + } + + public int getSizeAfterJumpTo() { + return mList.getSizeAfterJumpTo(); + + } + + ListEnumeration(RequestQueue queue, IDBVirtualList list) { + mQueue = queue; + mList = list; + } + + protected RequestQueue mQueue; + protected IDBVirtualList mList; +} diff --git a/base/common/src/com/netscape/cmscore/request/RequestRecord.java b/base/common/src/com/netscape/cmscore/request/RequestRecord.java new file mode 100644 index 000000000..1d066f0ad --- /dev/null +++ b/base/common/src/com/netscape/cmscore/request/RequestRecord.java @@ -0,0 +1,883 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program 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; version 2 of the License. +// +// This program 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.request; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.math.BigInteger; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBDynAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.IDBRegistry; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestRecord; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.request.RequestStatus; +import com.netscape.certsrv.request.ldap.IRequestMod; +import com.netscape.cmscore.dbs.BigIntegerMapper; +import com.netscape.cmscore.dbs.DateMapper; +import com.netscape.cmscore.dbs.StringMapper; +import com.netscape.cmscore.util.Debug; + +// +// A request record is the stored version of a request. +// It has a set of attributes that are mapped into LDAP +// attributes for actual directory operations. +// +public class RequestRecord + extends ARequestRecord + implements IRequestRecord, IDBObj { + /** + * + */ + private static final long serialVersionUID = 8044665107558872084L; + + public RequestId getRequestId() { + return mRequestId; + } + + public Enumeration getAttrNames() { + return mAttrTable.keys(); + } + + // IDBObj.get + public Object get(String name) { + if (name.equals(IRequestRecord.ATTR_REQUEST_ID)) + return mRequestId; + else if (name.equals(IRequestRecord.ATTR_REQUEST_STATE)) + return mRequestState; + else if (name.equals(IRequestRecord.ATTR_REQUEST_TYPE)) + return mRequestType; + else if (name.equals(IRequestRecord.ATTR_MODIFY_TIME)) + return mModifyTime; + else if (name.equals(IRequestRecord.ATTR_CREATE_TIME)) + return mCreateTime; + else if (name.equals(IRequestRecord.ATTR_SOURCE_ID)) + return mSourceId; + else if (name.equals(IRequestRecord.ATTR_REQUEST_OWNER)) + return mOwner; + else if (name.equals(IRequestRecord.ATTR_EXT_DATA)) + return mExtData; + else { + RequestAttr ra = mAttrTable.get(name); + + if (ra != null) + return ra.get(this); + } + + return null; + } + + // IDBObj.set + @SuppressWarnings("unchecked") + public void set(String name, Object o) { + if (name.equals(IRequestRecord.ATTR_REQUEST_ID)) + mRequestId = (RequestId) o; + else if (name.equals(IRequestRecord.ATTR_REQUEST_STATE)) + mRequestState = (RequestStatus) o; + else if (name.equals(IRequestRecord.ATTR_REQUEST_TYPE)) + mRequestType = (String) o; + else if (name.equals(IRequestRecord.ATTR_CREATE_TIME)) + mCreateTime = (Date) o; + else if (name.equals(IRequestRecord.ATTR_MODIFY_TIME)) + mModifyTime = (Date) o; + else if (name.equals(IRequestRecord.ATTR_SOURCE_ID)) + mSourceId = (String) o; + else if (name.equals(IRequestRecord.ATTR_REQUEST_OWNER)) + mOwner = (String) o; + else if (name.equals(IRequestRecord.ATTR_EXT_DATA)) + mExtData = (Hashtable) o; + else { + RequestAttr ra = mAttrTable.get(name); + + if (ra != null) + ra.set(this, o); + } + } + + // IDBObj.delete + public void delete(String name) + throws EBaseException { + throw new EBaseException("Invalid call to delete"); + } + + // IDBObj.getElements + public Enumeration getElements() { + return mAttrs.elements(); + } + + // IDBObj.getSerializableAttrNames + public Enumeration getSerializableAttrNames() { + return mAttrs.elements(); + } + + // copy values from r to the local record + void add(IRequest r) throws EBaseException { + // Collect the values for the record + mRequestId = r.getRequestId(); + mRequestType = r.getRequestType(); + mRequestState = r.getRequestStatus(); + mSourceId = r.getSourceId(); + mOwner = r.getRequestOwner(); + mCreateTime = r.getCreationTime(); + mModifyTime = r.getModificationTime(); + mExtData = loadExtDataFromRequest(r); + + for (int i = 0; i < mRequestA.length; i++) { + mRequestA[i].add(r, this); + } + } + + void read(IRequestMod a, IRequest r) throws EBaseException { + a.modRequestStatus(r, mRequestState); + r.setSourceId(mSourceId); + r.setRequestOwner(mOwner); + a.modModificationTime(r, mModifyTime); + a.modCreationTime(r, mCreateTime); + storeExtDataIntoRequest(r); + + for (int i = 0; i < mRequestA.length; i++) { + mRequestA[i].read(a, r, this); + } + } + + static void mod(ModificationSet mods, IRequest r) throws EBaseException { + // + mods.add(IRequestRecord.ATTR_REQUEST_STATE, + Modification.MOD_REPLACE, r.getRequestStatus()); + + mods.add(IRequestRecord.ATTR_SOURCE_ID, + Modification.MOD_REPLACE, r.getSourceId()); + + mods.add(IRequestRecord.ATTR_REQUEST_OWNER, + Modification.MOD_REPLACE, r.getRequestOwner()); + + mods.add(IRequestRecord.ATTR_MODIFY_TIME, + Modification.MOD_REPLACE, r.getModificationTime()); + + mods.add(IRequestRecord.ATTR_EXT_DATA, + Modification.MOD_REPLACE, loadExtDataFromRequest(r)); + + for (int i = 0; i < mRequestA.length; i++) { + mRequestA[i].mod(mods, r); + } + } + + static void register(IDBSubsystem db) + throws EDBException { + IDBRegistry reg = db.getRegistry(); + + reg.registerObjectClass(RequestRecord.class.getName(), mOC); + + reg.registerAttribute(IRequestRecord.ATTR_REQUEST_ID, new RequestIdMapper()); + reg.registerAttribute(IRequestRecord.ATTR_REQUEST_STATE, new RequestStateMapper()); + reg.registerAttribute(IRequestRecord.ATTR_CREATE_TIME, + new DateMapper(Schema.LDAP_ATTR_CREATE_TIME)); + reg.registerAttribute(IRequestRecord.ATTR_MODIFY_TIME, + new DateMapper(Schema.LDAP_ATTR_MODIFY_TIME)); + reg.registerAttribute(IRequestRecord.ATTR_SOURCE_ID, + new StringMapper(Schema.LDAP_ATTR_SOURCE_ID)); + reg.registerAttribute(IRequestRecord.ATTR_REQUEST_OWNER, + new StringMapper(Schema.LDAP_ATTR_REQUEST_OWNER)); + ExtAttrDynMapper extAttrMapper = new ExtAttrDynMapper(); + reg.registerAttribute(IRequestRecord.ATTR_EXT_DATA, extAttrMapper); + reg.registerDynamicMapper(extAttrMapper); + + for (int i = 0; i < mRequestA.length; i++) { + RequestAttr ra = mRequestA[i]; + + reg.registerAttribute(ra.mAttrName, ra.mMapper); + } + } + + protected static final String mOC[] = + { Schema.LDAP_OC_TOP, Schema.LDAP_OC_REQUEST, Schema.LDAP_OC_EXTENSIBLE }; + + protected static Hashtable loadExtDataFromRequest(IRequest r) throws EBaseException { + Hashtable h = new Hashtable(); + + Enumeration e = r.getExtDataKeys(); + while (e.hasMoreElements()) { + String key = e.nextElement(); + if (r.isSimpleExtDataValue(key)) { + h.put(key, r.getExtDataInString(key)); + } else { + h.put(key, r.getExtDataInHashtable(key)); + } + } + + return h; + } + + @SuppressWarnings("unchecked") + protected void storeExtDataIntoRequest(IRequest r) throws EBaseException { + Enumeration e = mExtData.keys(); + while (e.hasMoreElements()) { + String key = e.nextElement(); + Object value = mExtData.get(key); + if (value instanceof String) { + r.setExtData(key, (String) value); + } else if (value instanceof Hashtable) { + r.setExtData(key, (Hashtable) value); + } else { + throw new EDBException("Illegal data value in RequestRecord: " + + r.toString()); + } + } + } + + protected static Vector mAttrs = new Vector(); + + static Hashtable mAttrTable = new Hashtable(); + + /* + * This table contains attribute handlers for attributes + * of the request. These attributes are ones that are stored + * apart from the generic name/value pairs supported by the get/set + * interface plus the hashtable for the name/value pairs themselves. + * + * NOTE: Eventually, all attributes should be done here. Currently + * only the last ones added are implemented this way. + */ + static RequestAttr mRequestA[] = { + + new RequestAttr(IRequest.ATTR_REQUEST_TYPE, + new StringMapper(Schema.LDAP_ATTR_REQUEST_TYPE)) { + void set(ARequestRecord r, Object o) { + r.mRequestType = (String) o; + } + + Object get(ARequestRecord r) { + return r.mRequestType; + } + + void read(IRequestMod a, IRequest r, ARequestRecord rr) { + r.setRequestType(rr.mRequestType); + } + + void add(IRequest r, ARequestRecord rr) { + rr.mRequestType = r.getRequestType(); + } + + void mod(ModificationSet mods, IRequest r) { + addmod(mods, r.getRequestType()); + } + } + + }; + static { + mAttrs.add(IRequestRecord.ATTR_REQUEST_ID); + mAttrs.add(IRequestRecord.ATTR_REQUEST_STATE); + mAttrs.add(IRequestRecord.ATTR_CREATE_TIME); + mAttrs.add(IRequestRecord.ATTR_MODIFY_TIME); + mAttrs.add(IRequestRecord.ATTR_SOURCE_ID); + mAttrs.add(IRequestRecord.ATTR_REQUEST_OWNER); + mAttrs.add(IRequestRecord.ATTR_EXT_DATA); + + for (int i = 0; i < mRequestA.length; i++) { + RequestAttr ra = mRequestA[i]; + + mAttrs.add(ra.mAttrName); + mAttrTable.put(ra.mAttrName, ra); + } + } + +} + +// +// A mapper between an request state object and +// its LDAP attribute representation +//

+// +// @author thayes +// @version $Revision$ $Date$ +// +class RequestStateMapper + implements IDBAttrMapper { + // IDBAttrMapper methods + + // + // + public Enumeration getSupportedLDAPAttributeNames() { + return mAttrs.elements(); + } + + // + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) { + RequestStatus rs = (RequestStatus) obj; + + attrs.add(new LDAPAttribute(Schema.LDAP_ATTR_REQUEST_STATE, + rs.toString())); + } + + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) + throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(Schema.LDAP_ATTR_REQUEST_STATE); + + if (attr == null) + throw new EBaseException("schema violation"); + + String value = (String) attr.getStringValues().nextElement(); + + parent.set(name, RequestStatus.fromString(value)); + } + + public String mapSearchFilter(String name, String op, String value) { + return Schema.LDAP_ATTR_REQUEST_STATE + op + value; + } + + protected final static Vector mAttrs = new Vector(); + + static { + mAttrs.add(Schema.LDAP_ATTR_REQUEST_STATE); + } +} + +// +// A mapper between an request id object and +// its LDAP attribute representation +//

+// +// @author thayes +// @version $Revision$ $Date$ +// +class RequestIdMapper + implements IDBAttrMapper { + // IDBAttrMapper methods + + // + // + public Enumeration getSupportedLDAPAttributeNames() { + return mAttrs.elements(); + } + + // + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) { + RequestId rid = (RequestId) obj; + + String v = BigIntegerMapper.BigIntegerToDB(new BigInteger(rid.toString())); + + attrs.add(new LDAPAttribute(Schema.LDAP_ATTR_REQUEST_ID, v)); + } + + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) + throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(Schema.LDAP_ATTR_REQUEST_ID); + + if (attr == null) + throw new EBaseException("schema violation"); + + String value = (String) attr.getStringValues().nextElement(); + + parent.set(name, new RequestId( + BigIntegerMapper.BigIntegerFromDB(value).toString())); + } + + public String mapSearchFilter(String name, String op, String value) { + String v = null; + + try { + v = BigIntegerMapper.BigIntegerToDB(new BigInteger(value)); + } catch (NumberFormatException e) { + v = value; + } + return Schema.LDAP_ATTR_REQUEST_ID + op + v; + } + + protected final static Vector mAttrs = new Vector(); + + static { + mAttrs.add(Schema.LDAP_ATTR_REQUEST_ID); + } +} + +/** + * A mapper between an request attr set and its LDAP attribute representation. + * + * The attr attribute is no longer used. This class is kept for historical + * and migration purposes. + * + * @author thayes + * @version $Revision$ $Date$ + * @deprecated + */ +class RequestAttrsMapper + implements IDBAttrMapper { + // IDBAttrMapper methods + + // + // + public Enumeration getSupportedLDAPAttributeNames() { + return mAttrs.elements(); + } + + // + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) { + @SuppressWarnings("unchecked") + Hashtable ht = (Hashtable) obj; + Enumeration e = ht.keys(); + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream os = new ObjectOutputStream(bos); + + String key = null; + Object value = null; + + while (e.hasMoreElements()) { + key = e.nextElement(); + value = ht.get(key); + byte data[] = null; + + try { + data = encode(value); + os.writeObject(key); + os.writeObject(data); + } catch (NotSerializableException x) { + if (Debug.ON) { + System.err.println("Error: attribute '" + key + "' (" + + x.getMessage() + ") is not serializable"); + x.printStackTrace(); + } + } catch (Exception x) { + if (Debug.ON) { + System.err.println("Error: attribute '" + key + + "' - error during serialization: " + x); + x.printStackTrace(); + } + } + } + + os.writeObject(null); + os.close(); + + attrs.add(new LDAPAttribute(Schema.LDAP_ATTR_REQUEST_ATTRS, + bos.toByteArray())); + } catch (Exception x) { + Debug.trace("Output Mapping Error in requeset ID " + + ((RequestRecord) parent).getRequestId().toString() + " : " + x); + //if (Debug.ON) { + Debug.printStackTrace(x); + //} + } + } + + private byte[] encode(Object value) + throws NotSerializableException, IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream os = new ObjectOutputStream(bos); + + os.writeObject(value); + os.close(); + + return bos.toByteArray(); + } + + private Object decode(byte[] data) + throws ObjectStreamException, IOException, ClassNotFoundException { + ByteArrayInputStream bis = new ByteArrayInputStream(data); + ObjectInputStream is = new ObjectInputStream(bis); + + return is.readObject(); + } + + private Hashtable decodeHashtable(byte[] data) + throws ObjectStreamException, IOException, ClassNotFoundException { + Hashtable ht = new Hashtable(); + ByteArrayInputStream bis = new ByteArrayInputStream(data); + ObjectInputStream is = new ObjectInputStream(bis); + + String key = null; + + try { + + while (true) { + key = (String) is.readObject(); + + // end of table is marked with null + if (key == null) + break; + + byte[] bytes = (byte[]) is.readObject(); + + ht.put(key, decode(bytes)); + } + } catch (ObjectStreamException e) { + Debug.trace("Key " + key); // would be nice to know object type. + throw e; + } catch (IOException e) { + Debug.trace("Key " + key); // would be nice to know object type. + throw e; + } catch (ClassNotFoundException e) { + Debug.trace("Key " + key); // would be nice to know object type. + throw e; + } + + return ht; + } + + /** + * Implements IDBAttrMapper.mapLDAPAttributeSetToObject + *

+ * + * @see IDBAttrMapper#mapLDAPAttributeSetToObject + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) + throws EBaseException { + Hashtable ht = null; + + // + // Data is stored in a (single valued) binary attribute + // + byte[] value; + + LDAPAttribute attr = null; + + try { + attr = attrs.getAttribute(Schema.LDAP_ATTR_REQUEST_ATTRS); + + if (attr != null) { + @SuppressWarnings("unchecked") + Enumeration values = attr.getByteValues(); + + value = (byte[]) values.nextElement(); + + ht = decodeHashtable(value); + } + } catch (Exception x) { + Debug.trace("Mapping error in request Id " + + ((RequestRecord) parent).getRequestId().toString() + " : " + x); + Debug.trace("Attr " + attr.getName()); + //if (Debug.ON) { + Debug.printStackTrace(x); + //} + } + + parent.set(name, ht); + } + + public String mapSearchFilter(String name, String op, String value) { + return Schema.LDAP_ATTR_REQUEST_ID + op + value; + } + + protected final static Vector mAttrs = new Vector(); + + static { + mAttrs.add(Schema.LDAP_ATTR_REQUEST_ATTRS); + } +} + +/** + * Maps dynamic data for the extData- prefix to and from the extData Hashtable + * in RequestRecord. + * + * The data in RequestRecord is stored in a Hashtable. It comes in two forms: + * 1. String key1 => String value1 + * String key2 => String value2 + * This is stored in LDAP as: + * extData-key1 => value1 + * extData-key2 => value2 + * + * 2. String key => Hashtable value + * where value stores: + * String key2 => String value2 + * String key3 => String value3 + * This is stored in LDAP as: + * extData-key;key2 => value2 + * extData-key;key3 => value3 + * + * These can be mixed, but each top-level key can only be associated with + * a String value or a Hashtable value. + * + */ +class ExtAttrDynMapper implements IDBDynAttrMapper { + + public boolean supportsLDAPAttributeName(String attrName) { + return (attrName != null) && + attrName.toLowerCase().startsWith(extAttrPrefix); + } + + public Enumeration getSupportedLDAPAttributeNames() { + return mAttrs.elements(); + } + + /** + * Decodes extdata encoded keys. + * -- followed by a 4 digit hexadecimal string is decoded to the character + * representing the hex string. + * + * The routine is written to be highly efficient. It only allocates + * the StringBuffer if needed and copies the pieces in large chunks. + * + * @param key The key to decode + * @return The decoded key. + */ + public String decodeKey(String key) { + StringBuffer output = null; + char[] input = key.toCharArray(); + int startCopyIndex = 0; + + int index = 0; + while (index < input.length) { + if (input[index] == '-') { + if (((index + 1) < input.length) && + (input[index + 1] == '-')) { + if (output == null) { + output = new StringBuffer(input.length); + } + output.append(input, startCopyIndex, index - startCopyIndex); + index += 2; + if ((index + 3) < input.length) { + output.append( + Character.toChars( + Integer.parseInt(new String(input, index, 4), + 16)) + ); + } + index += 4; + startCopyIndex = index; + } else { + index++; + } + } else { + index++; + } + } + + if (output == null) { + return key; + } else { + output.append(input, startCopyIndex, index - startCopyIndex); + return output.toString(); + } + } + + /** + * Encoded extdata keys for storage in LDAP. + * + * The rules for encoding are trickier than decoding. We want to allow + * '-' by itself to be stored in the database (for the common case of keys + * like 'Foo-Bar'. Therefore we are using '--' as the encoding character. + * The rules are: + * 1) All characters [^-a-zA-Z0-9] are encoded as --XXXX where XXXX is the + * hex representation of the digit. + * 2) [a-zA-Z0-9] are always passed through unencoded + * 3) [-] is passed through as long as it is preceded and followed + * by [a-zA-Z0-9] (or if it's at the beginning/end of the string) + * 4) If [-] is preceded or followed by [^a-zA-Z0-9] then + * the - as well as all following [^a-zA-Z0-9] characters are encoded + * as --XXXX. + * + * This routine tries to be as efficient as possible with StringBuffer and + * large copies. However, the encoding unfortunately requires several + * objects to be allocated. + * + * @param key The key to encode + * @return The encoded key + */ + public String encodeKey(String key) { + StringBuffer output = null; + char[] input = key.toCharArray(); + int startCopyIndex = 0; + + int index = 0; + while (index < input.length) { + if (!isAlphaNum(input[index])) { + if ((input[index] == '-') && + ((index + 1) < input.length) && + (isAlphaNum(input[index + 1]))) { + index += 2; + } else if ((input[index] == '-') && + ((index + 1) == input.length)) { + index += 1; + } else { + if (output == null) { + output = new StringBuffer(input.length + 5); + } + output.append(input, startCopyIndex, index - startCopyIndex); + while ((index < input.length) && + (!isAlphaNum(input[index]))) { + output.append("--"); + String hexString = Integer.toHexString(input[index]); + int padding = 4 - hexString.length(); + while (padding > 0) { + output.append('0'); + padding--; + } + output.append(hexString); + index++; + } + startCopyIndex = index; + } + } else { + index++; + } + } + + if (output == null) { + return key; + } else { + output.append(input, startCopyIndex, index - startCopyIndex); + return output.toString(); + } + } + + protected boolean isAlphaNum(char in) { + if ((in >= 'a') && (in <= 'z')) { + return true; + } + if ((in >= 'A') && (in <= 'Z')) { + return true; + } + if ((in >= '0') && (in <= '9')) { + return true; + } + return false; + } + + public void mapObjectToLDAPAttributeSet(IDBObj parent, String name, + Object obj, LDAPAttributeSet attrs) + throws EBaseException { + @SuppressWarnings("unchecked") + Hashtable ht = (Hashtable) obj; + Enumeration e = ht.keys(); + + try { + while (e.hasMoreElements()) { + String key = e.nextElement(); + Object value = ht.get(key); + if (value instanceof String) { + String stringValue = (String) value; + attrs.add(new LDAPAttribute( + extAttrPrefix + encodeKey(key), + stringValue)); + } else if (value instanceof Hashtable) { + @SuppressWarnings("unchecked") + Hashtable innerHash = (Hashtable) value; + Enumeration innerHashEnum = innerHash.keys(); + while (innerHashEnum.hasMoreElements()) { + String innerKey = innerHashEnum.nextElement(); + String innerValue = innerHash.get(innerKey); + attrs.add(new LDAPAttribute( + extAttrPrefix + encodeKey(key) + ";" + encodeKey(innerKey), + innerValue)); + } + } + } + } catch (Exception x) { + Debug.trace("Output Mapping Error in requeset ID " + + ((IRequestRecord) parent).getRequestId().toString() + " : " + x); + //if (Debug.ON) { + Debug.printStackTrace(x); + //} + } + } + + @SuppressWarnings("unchecked") + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, String name, + IDBObj parent) + throws EBaseException { + Hashtable ht = new Hashtable(); + Hashtable valueHashtable; + + Enumeration attrEnum = attrs.getAttributes(); + while (attrEnum.hasMoreElements()) { + LDAPAttribute attr = attrEnum.nextElement(); + String baseName = attr.getBaseName(); + if (baseName.toLowerCase().startsWith(extAttrPrefix)) { + String keyName = decodeKey( + baseName.substring(extAttrPrefix.length())); + String[] subTypes = attr.getSubtypes(); + String[] values = attr.getStringValueArray(); + if (values.length != 1) { + String message = "Output Mapping Error in request ID " + + ((IRequestRecord) parent).getRequestId().toString() + " : " + + "more than one value returned for " + + keyName; + Debug.trace(message); + throw new EBaseException(message); + } + if ((subTypes != null) && (subTypes.length > 0)) { + if (subTypes.length != 1) { + String message = "Output Mapping Error in request ID " + + ((IRequestRecord) parent).getRequestId().toString() + " : " + + "more than one subType returned for " + + keyName; + Debug.trace(message); + throw new EBaseException(message); + } + Object value = ht.get(keyName); + if ((value != null) && (!(value instanceof Hashtable))) { + String message = "Output Mapping Error in request ID " + + ((IRequestRecord) parent).getRequestId().toString() + " : " + + "combined no-subtype and subtype data for key " + + keyName; + Debug.trace(message); + throw new EBaseException(message); + } + valueHashtable = (Hashtable) value; + if (valueHashtable == null) { + valueHashtable = new Hashtable(); + ht.put(keyName, valueHashtable); + } + valueHashtable.put(decodeKey(subTypes[0]), values[0]); + } else { + ht.put(keyName, values[0]); + } + } + } + + parent.set(name, ht); + } + + public String mapSearchFilter(String name, String op, String value) throws EBaseException { + return name + op + value; + } + + protected final static String extAttrPrefix = "extdata-"; + + protected final static Vector mAttrs = new Vector(); + + static { + mAttrs.add(Schema.LDAP_ATTR_EXT_ATTR); + } +} diff --git a/base/common/src/com/netscape/cmscore/request/RequestRepository.java b/base/common/src/com/netscape/cmscore/request/RequestRepository.java new file mode 100644 index 000000000..0a4a4ebf9 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/request/RequestRepository.java @@ -0,0 +1,217 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program 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; version 2 of the License. +// +// This program 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.request; + +import java.math.BigInteger; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSearchResults; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.dbs.repository.IRepositoryRecord; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.cmscore.dbs.Repository; +import com.netscape.cmscore.dbs.RepositoryRecord; + +/** + * TODO: what does this class provide beyond the Repository + * base class?? + *

+ * + * @author thayes + * @version $Revision$ $Date$ + */ +class RequestRepository + extends Repository { + + IDBSubsystem mDB = null; + IRequestQueue mRequestQueue = null; + + /** + * Create a request repository that uses the LDAP database + *

+ * + * @param name + * the name of the repository. This String is used to + * construct the DN for the repository's LDAP entry. + * @param db + * the LDAP database system. + */ + public RequestRepository(String name, int increment, IDBSubsystem db) + throws EDBException { + super(db, increment, "ou=" + name + ",ou=requests," + db.getBaseDN()); + + CMS.debug("RequestRepository: constructor 1"); + mBaseDN = "ou=" + name + ",ou=requests," + db.getBaseDN(); + + // Let RequestRecord class register its + // database mapping and object mapping values + RequestRecord.register(db); + mDB = db; + } + + public RequestRepository(String name, int increment, IDBSubsystem db, IRequestQueue requestQueue) + throws EDBException { + super(db, increment, "ou=" + name + ",ou=requests," + db.getBaseDN()); + + CMS.debug("RequestRepository: constructor2."); + mRequestQueue = requestQueue; + mBaseDN = "ou=" + name + ",ou=requests," + db.getBaseDN(); + + // Let RequestRecord class register its + // database mapping and object mapping values + RequestRecord.register(db); + mDB = db; + } + + /** + * get the LDAP base DN for this repository. This + * value can be used by the request queue to create the + * name for the request records themselves. + *

+ * + * @return + * the LDAP base DN. + */ + public String getBaseDN() { + return mBaseDN; + } + + /** + * Resets serial number. + */ + public void resetSerialNumber(BigInteger serial) throws EBaseException { + setTheSerialNumber(serial); + } + + /** + * Removes all objects with this repository. + */ + public void removeAllObjects() throws EBaseException { + IDBSSession s = mDB.createSession(); + try { + IDBSearchResults sr = s.search(getBaseDN(), + "(" + RequestRecord.ATTR_REQUEST_ID + "=*)"); + while (sr.hasMoreElements()) { + RequestRecord r = (RequestRecord) sr.nextElement(); + String name = "cn" + "=" + + r.getRequestId().toString() + "," + getBaseDN(); + s.delete(name); + } + } finally { + if (s != null) + s.close(); + } + } + + public BigInteger getLastSerialNumberInRange(BigInteger min, BigInteger max) { + + CMS.debug("RequestRepository: in getLastSerialNumberInRange: min " + min + " max " + max); + + CMS.debug("RequestRepository: mRequestQueue " + mRequestQueue); + + BigInteger ret = null; + + if (mRequestQueue == null) { + + CMS.debug("RequestRepository: mRequestQueue is null."); + + } else { + + CMS.debug("RequestRepository: about to call mRequestQueue.getLastRequestIdInRange"); + ret = mRequestQueue.getLastRequestIdInRange(min, max); + + } + + return ret; + + } + + /** + * the LDAP base DN for this repository + */ + protected String mBaseDN; + + public String getPublishingStatus() { + RepositoryRecord record = null; + Object obj = null; + IDBSSession dbs = null; + String status = null; + + try { + dbs = mDB.createSession(); + obj = dbs.read(mBaseDN); + } catch (Exception e) { + CMS.debug("RequestRepository: getPublishingStatus: Error: " + e); + CMS.debugStackTrace(); + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) { + try { + dbs.close(); + } catch (Exception ex) { + CMS.debug("RequestRepository: getPublishingStatus: Error: " + ex); + } + } + } + + if (obj != null || (obj instanceof RepositoryRecord)) { + record = (RepositoryRecord) obj; + status = record.getPublishingStatus(); + } else { + CMS.debug("RequestRepository: obj is NOT instanceof RepositoryRecord"); + } + CMS.debug("RequestRepository: getPublishingStatus mBaseDN: " + mBaseDN + + " status: " + ((status != null) ? status : "null")); + + return status; + } + + public void setPublishingStatus(String status) { + IDBSSession dbs = null; + + CMS.debug("RequestRepository: setPublishingStatus mBaseDN: " + mBaseDN + " status: " + status); + ModificationSet mods = new ModificationSet(); + + if (status != null && status.length() > 0) { + mods.add(IRepositoryRecord.ATTR_PUB_STATUS, + Modification.MOD_REPLACE, status); + + try { + dbs = mDB.createSession(); + dbs.modify(mBaseDN, mods); + } catch (Exception e) { + CMS.debug("RequestRepository: setPublishingStatus: Error: " + e); + CMS.debugStackTrace(); + } finally { + // Close session - ignoring errors (UTIL) + if (dbs != null) { + try { + dbs.close(); + } catch (Exception ex) { + CMS.debug("RequestRepository: setPublishingStatus: Error: " + ex); + } + } + } + } + } +} diff --git a/base/common/src/com/netscape/cmscore/request/RequestSubsystem.java b/base/common/src/com/netscape/cmscore/request/RequestSubsystem.java new file mode 100644 index 000000000..862ddaa68 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/request/RequestSubsystem.java @@ -0,0 +1,187 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program 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; version 2 of the License. +// +// This program 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.request; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.request.INotify; +import com.netscape.certsrv.request.IPolicy; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.IRequestSubsystem; +import com.netscape.certsrv.request.IService; +import com.netscape.cmscore.dbs.DBSubsystem; + +/** + * RequestSubsystem + *

+ * This class is reponsible for managing storage of request objects in the local database. + *

+ * TODO: review this It provides: + registration of LDAP/JAVA mapping classes with the DBSubsystem + creation of + * RequestQueue storage in the database + retrieval of existing RequestQueue objects from the database + *

+ * + * @author thayes + * @version $Revision$, $Date$ + */ +public class RequestSubsystem + implements IRequestSubsystem, ISubsystem { + + public final static String ID = IRequestSubsystem.SUB_ID; + + // singleton enforcement + + private static RequestSubsystem mInstance = new RequestSubsystem(); + + public static RequestSubsystem getInstance() { + return mInstance; + } + + private RequestSubsystem() { + } + + // end singleton enforcement. + + // + // Create a new request queue. The LDAP DN for the entry + // in the database is supplied by the caller. + // + public void createRequestQueue(String name) + throws EBaseException { + + /* + String dbName = makeQueueName(name); + IDBSSession dbs = createDBSSession(); + + // Create Repository record here + + dbs.add(dbName, r); + */ + } + + public IRequestQueue + getRequestQueue(String name, int increment, IPolicy p, IService s, INotify n) + throws EBaseException { + return getRequestQueue(name, increment, p, s, n, null); + } + + public IRequestQueue + getRequestQueue(String name, int increment, IPolicy p, IService s, INotify n, + INotify pendingNotifier) + throws EBaseException { + RequestQueue rq = new RequestQueue(name, increment, p, s, n, pendingNotifier); + + // can't do this here because the service depends on getting rq + // (to get request) and since this method hasn't returned it's rq is null. + //rq.recover(); + + return rq; + } + + // + // ISubsystem methods: + // getId, setId, init, startup, shutdown, getConfigStore + // + + /** + * Implements ISubsystem.getId + *

+ * + * @see ISubsystem#getId + */ + public String getId() { + return mId; + } + + // ISubsystem.setId + public void setId(String id) + throws EBaseException { + mId = id; + } + + // ISubsystem.init + public void init(ISubsystem parent, IConfigStore config) { + mParent = parent; + mConfig = config; + } + + /** + * Implements ISubsystem.startup + *

+ * + * @see ISubsystem#startup + */ + public void startup() + throws EBaseException { + mLogger = CMS.getLogger(); + + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_REQQUEUE, ILogger.LL_INFO, + "Request subsystem started"); + } + + public void shutdown() { + mRequestQueue = null; + + if (mLogger != null) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_REQQUEUE, ILogger.LL_INFO, + "Request subsystem stopped"); + } + } + + public IConfigStore getConfigStore() { + return mConfig; + } + + // + // Access to the DBSubsystem environment value + // + protected IDBSubsystem getDBSubsystem() { + return DBSubsystem.getInstance(); + } + + // + // Create a database session in the default database + // system. + // + protected IDBSSession createDBSSession() + throws EBaseException { + return getDBSubsystem().createSession(); + } + + // + // Make a queue name + // + protected String makeQueueName(String name) { + IDBSubsystem db = getDBSubsystem(); + + return "cn=" + name + "," + db.getBaseDN(); + } + + // Instance variables + + private IConfigStore mConfig; + private ISubsystem mParent; + private String mId = IRequestSubsystem.SUB_ID; + private IRequestQueue mRequestQueue; + + protected ILogger mLogger; +} diff --git a/base/common/src/com/netscape/cmscore/request/Schema.java b/base/common/src/com/netscape/cmscore/request/Schema.java new file mode 100644 index 000000000..89a7b74b9 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/request/Schema.java @@ -0,0 +1,50 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program 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; version 2 of the License. +// +// This program 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.request; + +// +// The Schema class contains constant string values for +// LDAP attribute and object class names used in this package +// +class Schema { + public static final String LDAP_OC_TOP = "top"; + public static final String LDAP_OC_REQUEST = "request"; + public static final String LDAP_OC_EXTENSIBLE = "extensibleObject"; + + public static final String LDAP_ATTR_REQUEST_ID = "requestId"; + public static final String LDAP_ATTR_REQUEST_STATE = "requestState"; + public static final String LDAP_ATTR_CREATE_TIME = "dateOfCreate"; + public static final String LDAP_ATTR_MODIFY_TIME = "dateOfModify"; + public static final String LDAP_ATTR_REQUEST_XATTRS = "adminMessages"; + public static final String LDAP_ATTR_SOURCE_ID = "requestSourceId"; + + public static final String LDAP_ATTR_REQUEST_OWNER = "requestOwner"; + public static final String LDAP_ATTR_REQUEST_ATTRS = "requestAttributes"; + public static final String LDAP_ATTR_AGENT_GROUP = "requestAgentGroup"; + public static final String LDAP_ATTR_REQUEST_TYPE = "requestType"; + public static final String LDAP_ATTR_REQUEST_ERROR = "requestError"; + + // This attribute is a placeholder used by ExtAttrDynMapper + public static final String LDAP_ATTR_EXT_ATTR = "extAttr"; + + // Indicates a special state that may be searched for exactly + // such as requiresAgentService. The idea is to reduce the space + // used in indexes to optimize common queries. + // NOT IMPLEMENTED + public static final String LDAP_ATTR_REQUEST_FLAG = "requestFlag"; +} -- cgit