001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.lenya.cms.workflow;
019:
020: import java.text.ParsePosition;
021: import java.text.SimpleDateFormat;
022: import java.util.Date;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.Locale;
026: import java.util.Map;
027: import java.util.SortedMap;
028: import java.util.TreeMap;
029:
030: import org.apache.avalon.framework.container.ContainerUtil;
031: import org.apache.avalon.framework.logger.AbstractLogEnabled;
032: import org.apache.avalon.framework.logger.Logger;
033: import org.apache.avalon.framework.service.ServiceManager;
034: import org.apache.lenya.ac.Identity;
035: import org.apache.lenya.ac.User;
036: import org.apache.lenya.cms.metadata.MetaData;
037: import org.apache.lenya.cms.observation.RepositoryEvent;
038: import org.apache.lenya.cms.observation.RepositoryEventFactory;
039: import org.apache.lenya.cms.publication.Document;
040: import org.apache.lenya.cms.publication.ResourceType;
041: import org.apache.lenya.cms.repository.Session;
042: import org.apache.lenya.workflow.Version;
043: import org.apache.lenya.workflow.Workflow;
044: import org.apache.lenya.workflow.Workflowable;
045:
046: /**
047: * Workflowable around a CMS document.
048: *
049: * @version $Id: DocumentWorkflowable.java 416648 2006-06-23 09:15:28Z andreas $
050: */
051: class DocumentWorkflowable extends AbstractLogEnabled implements
052: Workflowable {
053:
054: /**
055: * Ctor.
056: * @param manager The service manager.
057: * @param session The repository session.
058: * @param document The document.
059: * @param logger The logger.
060: */
061: public DocumentWorkflowable(ServiceManager manager,
062: Session session, Document document, Logger logger) {
063: this .document = document;
064: this .session = session;
065: this .manager = manager;
066: ContainerUtil.enableLogging(this , logger);
067: }
068:
069: private Session session;
070:
071: private ServiceManager manager;
072:
073: /**
074: * @return The service manager.
075: */
076: public ServiceManager getServiceManager() {
077: return this .manager;
078: }
079:
080: /**
081: * @return The repository session.
082: */
083: public Session getSession() {
084: return session;
085: }
086:
087: private Document document;
088:
089: protected Document getDocument() {
090: return this .document;
091: }
092:
093: /**
094: * @return The name of the workflow schema.
095: */
096: protected String getWorkflowSchema() {
097: String workflowName = null;
098: try {
099: ResourceType doctype = document.getResourceType();
100: if (doctype != null) {
101: workflowName = document.getPublication()
102: .getWorkflowSchema(doctype);
103: }
104: } catch (Exception e) {
105: throw new RuntimeException(e);
106: }
107: return workflowName;
108: }
109:
110: private Version[] versions = null;
111:
112: private long lastModified = 0;
113:
114: protected static final String METADATA_NAMESPACE = "http://apache.org/lenya/metadata/workflow/1.0";
115: protected static final String METADATA_VERSION = "workflowVersion";
116:
117: /**
118: * @see org.apache.lenya.workflow.Workflowable#getVersions()
119: */
120: public Version[] getVersions() {
121: try {
122: MetaData meta = this .document
123: .getMetaData(METADATA_NAMESPACE);
124: if (this .versions == null
125: || meta.getLastModified() > this .lastModified) {
126: String[] versionStrings = meta
127: .getValues(METADATA_VERSION);
128: this .versions = new Version[versionStrings.length];
129:
130: SortedMap number2version = new TreeMap();
131:
132: for (int i = 0; i < versionStrings.length; i++) {
133: String string = versionStrings[i];
134: int spaceIndex = string.indexOf(" ");
135: String numberString = string.substring(0,
136: spaceIndex);
137: int number = Integer.parseInt(numberString);
138: String versionString = string
139: .substring(spaceIndex + 1);
140: Version version = decodeVersion(versionString);
141: number2version.put(new Integer(number), version);
142: }
143:
144: int number = 0;
145: for (Iterator i = number2version.keySet().iterator(); i
146: .hasNext();) {
147: Version version = (Version) number2version.get(i
148: .next());
149: this .versions[number] = version;
150: number++;
151: }
152:
153: this .lastModified = meta.getLastModified();
154: }
155: } catch (Exception e) {
156: throw new RuntimeException(e);
157: }
158: return this .versions;
159: }
160:
161: /**
162: * @see org.apache.lenya.workflow.Workflowable#getLatestVersion()
163: */
164: public Version getLatestVersion() {
165: Version version = null;
166: Version[] versions = getVersions();
167: if (versions.length > 0) {
168: version = versions[versions.length - 1];
169: }
170: return version;
171: }
172:
173: /**
174: * @see org.apache.lenya.workflow.Workflowable#newVersion(org.apache.lenya.workflow.Workflow,
175: * org.apache.lenya.workflow.Version)
176: */
177: public void newVersion(Workflow workflow, Version version) {
178: Version[] newVersions = new Version[getVersions().length + 1];
179: for (int i = 0; i < getVersions().length; i++) {
180: newVersions[i] = getVersions()[i];
181: }
182:
183: int number = newVersions.length - 1;
184: newVersions[number] = version;
185:
186: String string = number + " " + encodeVersion(workflow, version);
187: addToMetaData(string);
188:
189: WorkflowEventDescriptor descriptor = new WorkflowEventDescriptor(
190: version);
191: RepositoryEvent event = RepositoryEventFactory.createEvent(
192: this .manager, getDocument(), getLogger(), descriptor);
193: getDocument().getRepositoryNode().getSession().enqueueEvent(
194: event);
195: }
196:
197: protected void addToMetaData(String versionString) {
198: try {
199: String[] areas = getDocument().getPublication()
200: .getAreaNames();
201: for (int i = 0; i < areas.length; i++) {
202: if (getDocument().existsAreaVersion(areas[i])) {
203: Document doc = getDocument().getAreaVersion(
204: areas[i]);
205: MetaData meta = doc.getMetaData(METADATA_NAMESPACE);
206: meta.addValue(METADATA_VERSION, versionString);
207: }
208: }
209: } catch (Exception e) {
210: throw new RuntimeException(e);
211: }
212: }
213:
214: protected String encodeVersion(Workflow workflow, Version version) {
215:
216: StringBuffer stringBuf = new StringBuffer("event:")
217: .append(version.getEvent());
218: stringBuf.append(" state:").append(version.getState());
219:
220: Identity identity = getSession().getIdentity();
221: User user = identity.getUser();
222: if (user != null) {
223: stringBuf.append(" user:").append(
224: identity.getUser().getId());
225: }
226: stringBuf.append(" machine:").append(
227: identity.getMachine().getIp());
228:
229: SimpleDateFormat format = new SimpleDateFormat(
230: "yyyy-MM-dd_HH:mm:ss");
231: stringBuf.append(" date:").append(format.format(new Date()));
232:
233: String names[] = workflow.getVariableNames();
234: for (int i = 0; i < names.length; i++) {
235: String value = Boolean.toString(version.getValue(names[i]));
236: stringBuf.append(" var:").append(names[i]);
237: stringBuf.append("=").append(value);
238: }
239: return stringBuf.toString();
240: }
241:
242: protected Version decodeVersion(String string) {
243:
244: String event = null;
245: String state = null;
246: String user = null;
247: String machine = null;
248: Date date = null;
249: Map variables = new HashMap();
250:
251: String[] parts = string.split(" ");
252: for (int i = 0; i < parts.length; i++) {
253: String[] steps = parts[i].split(":", 2);
254: if (steps[0].equals("event")) {
255: event = steps[1];
256: } else if (steps[0].equals("state")) {
257: state = steps[1];
258: } else if (steps[0].equals("user")) {
259: user = steps[1];
260: } else if (steps[0].equals("date")) {
261: SimpleDateFormat sdf = new SimpleDateFormat(
262: "yyyy-MM-dd_HH:mm:ss", Locale.US);
263: date = sdf.parse(steps[1], new ParsePosition(0));
264: } else if (steps[0].equals("machine")) {
265: machine = steps[1];
266: } else if (steps[0].equals("var")) {
267: String[] nameValue = steps[1].split("=");
268: variables.put(nameValue[0], nameValue[1]);
269: }
270: }
271:
272: Version version = new LenyaVersion(event, state);
273: for (Iterator i = variables.keySet().iterator(); i.hasNext();) {
274: String name = (String) i.next();
275: String value = (String) variables.get(name);
276: version.setUserId(user);
277: version.setDate(date);
278: version.setIPAddress(machine);
279: version.setValue(name, Boolean.valueOf(value)
280: .booleanValue());
281: }
282: return version;
283: }
284:
285: /**
286: * @see org.apache.lenya.workflow.Workflowable#getWorkflowSchemaURI()
287: */
288: public String getWorkflowSchemaURI() {
289: String uri = null;
290: String schema = getWorkflowSchema();
291: if (schema != null) {
292:
293: if (schema.indexOf("://") != -1) {
294: return schema;
295: } else {
296: uri = this .document.getPublication().getSourceURI()
297: + "/config/workflow/" + schema;
298: uri = uri.substring("lenya://".length());
299: uri = "context://" + uri;
300: }
301: }
302: return uri;
303: }
304:
305: public String toString() {
306: return this.document.toString();
307: }
308:
309: }
|