/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.ode.bpel.engine.migration; import org.apache.ode.bpel.engine.BpelProcess; import org.apache.ode.bpel.engine.OutstandingRequestManager; import org.apache.ode.bpel.engine.ReplacementMapImpl; import org.apache.ode.bpel.runtime.Selector; import org.apache.ode.bpel.common.CorrelationKey; import org.apache.ode.bpel.common.CorrelationKeySet; import org.apache.ode.bpel.o.OProcess; import org.apache.ode.dao.bpel.BpelDAOConnection; import org.apache.ode.dao.bpel.ProcessDAO; import org.apache.ode.dao.bpel.ProcessInstanceDAO; import org.apache.ode.jacob.vpu.ExecutionQueueImpl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.xml.namespace.QName; import java.util.Set; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.io.ObjectStreamClass; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; /** * Migrates the database from using single correlations to multiple correlations support. */ public class CorrelationKeySetMigration implements Migration { private static final Log __log = LogFactory.getLog(CorrelationKeySetMigration.class); public boolean migrate(Set<BpelProcess> registeredProcesses, BpelDAOConnection connection) { boolean v1First = true; for (BpelProcess process : registeredProcesses) { ProcessDAO processDao = connection.getProcess(process.getConf().getProcessId()); Collection<ProcessInstanceDAO> pis = processDao.getActiveInstances(); // Migrate the correlation key stored in the jacob state of the instance for (ProcessInstanceDAO instance : pis) { __log.debug("Migrating correlation key in jacob for instance " + instance.getInstanceId()); OProcess oproc = findOProcess(registeredProcesses, instance.getProcess().getProcessId()); if (v1First) { if (!updateV1Key(instance, oproc)) { v1First = false; updateV2Key(instance, oproc); } } else { if (!updateV2Key(instance, oproc)) { v1First = true; updateV1Key(instance, oproc); } } } } return true; } private boolean updateV1Key(ProcessInstanceDAO instance, OProcess oproc) { ExecutionQueueImpl soup; try { soup = readOldState(instance, oproc, getClass().getClassLoader(), true); if (soup == null) return false; } catch (Exception e) { __log.debug(" failed to read a v1 state for instance " + instance.getInstanceId()); ExecutionQueueImpl._classDescriptors.clear(); return false; } try { OutstandingRequestManager orm = (OutstandingRequestManager) soup.getGlobalData(); for (OutstandingRequestManager.Entry entry : orm._byChannel.values()) { Selector[] newSelectors = new Selector[entry.selectors.length]; int index = 0; for (Object selector : entry.selectors) { OldSelector sel = (OldSelector)selector; Object selCKey = sel.correlationKey; if (selCKey != null) { OldCorrelationKey old = (OldCorrelationKey) selCKey; __log.debug(" Changing V1 key " + old.toCanonicalString()); CorrelationKeySet newKeySet = new CorrelationKeySet(); newKeySet.add(new CorrelationKey(""+old.getCSetId(), old.getValues())); Selector newSelector = new Selector(sel.idx, sel.plinkInstance, sel.opName, sel.oneWay, sel.messageExchangeId, newKeySet, "one"); newSelector.correlationKey = new CorrelationKey(""+old.getCSetId(), old.getValues()); newSelectors[index++] = newSelector; } } entry.selectors = newSelectors; } writeOldState(instance, soup); } finally { ExecutionQueueImpl._classDescriptors.clear(); } return true; } private boolean updateV2Key(ProcessInstanceDAO instance, OProcess oproc) { ExecutionQueueImpl soup; try { soup = readOldState(instance, oproc, getClass().getClassLoader(), false); if (soup == null) return false; } catch (Exception e) { __log.debug(" failed to read a v2 state for instance " + instance.getInstanceId()); ExecutionQueueImpl._classDescriptors.clear(); return false; } OutstandingRequestManager orm = (OutstandingRequestManager) soup.getGlobalData(); for (OutstandingRequestManager.Entry entry : orm._byChannel.values()) { Selector[] newSelectors = new Selector[entry.selectors.length]; int index = 0; for (Object selector : entry.selectors) { OldSelector sel = (OldSelector)selector; CorrelationKey selCKey = (CorrelationKey) sel.correlationKey; if (selCKey != null) { __log.debug(" Changing V2 key " + selCKey.toCanonicalString()); CorrelationKeySet newKeySet = new CorrelationKeySet(); newKeySet.add(new CorrelationKey(""+selCKey.getCorrelationSetName(), selCKey.getValues())); Selector newSelector = new Selector(sel.idx, sel.plinkInstance, sel.opName, sel.oneWay, sel.messageExchangeId, newKeySet, "one"); newSelector.correlationKey = new CorrelationKey(""+selCKey.getCorrelationSetName(), selCKey.getValues()); newSelectors[index++] = newSelector; } } entry.selectors = newSelectors; } writeOldState(instance, soup); return true; } private ExecutionQueueImpl readOldState(ProcessInstanceDAO instance, OProcess oprocess, ClassLoader cl, boolean changeKey) { if (instance.getExecutionState() == null) return null; try { ExecutionQueueImpl soup = new ExecutionQueueImpl(cl); ObjectStreamClass osc; if (changeKey) { osc = ObjectStreamClass.lookup(Class.forName( "org.apache.ode.bpel.engine.migration.OldCorrelationKey", true, cl)); ExecutionQueueImpl._classDescriptors.put("org.apache.ode.bpel.common.CorrelationKey", osc); } osc = ObjectStreamClass.lookup(Class.forName( "org.apache.ode.bpel.engine.migration.OldSelector", true, cl)); ExecutionQueueImpl._classDescriptors.put("org.apache.ode.bpel.runtime.Selector", osc); osc = ObjectStreamClass.lookup(Class.forName( "[Lorg.apache.ode.bpel.engine.migration.OldSelector;", true, getClass().getClassLoader())); ExecutionQueueImpl._classDescriptors.put("[Lorg.apache.ode.bpel.runtime.Selector;", osc); soup.setReplacementMap(new ReplacementMapImpl(oprocess)); ByteArrayInputStream iis = new ByteArrayInputStream(instance.getExecutionState()); soup.read(iis); return soup; } catch (Exception e) { throw new RuntimeException(e); } } private void writeOldState(ProcessInstanceDAO instance, ExecutionQueueImpl soup) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); soup.write(bos); bos.close(); instance.setExecutionState(bos.toByteArray()); ExecutionQueueImpl._classDescriptors.clear(); } catch (Exception e) { throw new RuntimeException(e); } } private OProcess findOProcess(Set<BpelProcess> registeredProcesses, QName name) { for (BpelProcess process : registeredProcesses) { if (process.getConf().getProcessId().equals(name)) return process.getOProcess(); } return null; } }