| /* |
| * 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.opennlp.ml.maxent; |
| |
| import org.apache.opennlp.ml.model.MaxentModel; |
| |
| /** |
| * A object which can be used to ensure that a Maxent application can swap the |
| * model currently in use with a new one in a thread-safe manner without |
| * stopping the servicing of requests. Use this if your maxent application is |
| * a heavy-weight one or you have only one particular MaxentModel to use with |
| * your application. If your application class is lightweight and you will be |
| * creating multiple instances of it with different underlying models, consider |
| * using a DomainToModelMap object to ensure thread-safe model swapping. |
| * |
| * <p>For example, in your application, create a ModelReplacementManager as |
| * follows: |
| * |
| * <pre> |
| * private final ModelReplacementManager replacementManager = |
| * new ModelReplacementManager( |
| * new ModelSetter() { |
| * public void setModel(MaxentModel m) { |
| * model = m; |
| * } |
| * } |
| * ); |
| * </pre> |
| * |
| * where "model" would be the actual variable name of the model used by your |
| * application which you wish to be able to swap (you might have other models |
| * which need their own ModelReplacementManager). |
| * |
| * <p>You'll also need a method to swap the model which calls the manager's |
| * replaceModel(MaxentModel m) method, e.g., |
| * |
| * <pre> |
| * public void replaceModel (MaxentModel newmod) { |
| * replacementManager.replaceModel(newmod); |
| * } |
| * </pre> |
| * |
| * Then, in the code that uses the model, you need to inform the |
| * ModelReplacementManager when a thread is beginning to use the model and when |
| * it no longer needs to be sure that the same model is being used. For |
| * example, it is quite common to evaluate a particular context, get back a |
| * double[] which has the normalized probabilities of each of the outcomes given |
| * that context, and then request the name of a particular outcome. The model |
| * cannot be swapped during that time since the mapping from outcome labels to |
| * unique will (probably) be different between the different models. So, do as |
| * follows: |
| * |
| * <pre> |
| * replacementManager.startUsingModel(); |
| * // some code which evaluates the context, e.g., |
| * double[] probs = model.eval(someContext); |
| * // some code which returns a particular outcome |
| * if (model.getBestOutcome(probs).equals("T") ... |
| * replacementManager.finishUsingModel(); |
| * </pre> |
| * |
| * The manager will then make sure that all requests which are currently being |
| * serviced are completed before the new model is swapped in. New requests |
| * which are made while the models are being swapped are forced to wait for the |
| * swap to finish. These requests will then be serviced by the new model. |
| */ |
| public class ModelReplacementManager { |
| private ModelSetter setter; |
| |
| private int users = 0; |
| private boolean replacementCanProceed = true; |
| private Thread replacementThread = null; |
| |
| public ModelReplacementManager(ModelSetter ms) { |
| setter = ms; |
| } |
| |
| /** |
| * Inform the manager that a thread is using the model. If a replacement is |
| * underway, the thread is forced to join the replacement thread and thus wait |
| * until it is finished to begin using the model. |
| */ |
| public void startUsingModel() { |
| if (replacementThread != null) { |
| try { |
| replacementThread.join(); |
| } catch (InterruptedException e) { |
| } |
| } |
| replacementCanProceed = false; |
| users++; |
| } |
| |
| /** |
| * Inform the manager that a thread is done using the model, and thus is not |
| * dependending on it being unchanged. |
| */ |
| public void finishUsingModel() { |
| users--; |
| if (users <= 0) |
| replacementCanProceed = true; |
| } |
| |
| /** |
| * Replace the old model with a new one, forcing the replacement to wait until |
| * all threads using the old model have finished using it. |
| * |
| * @param model |
| * The new model which is being swapped in. |
| */ |
| public synchronized void replaceModel(MaxentModel model) { |
| replacementThread = Thread.currentThread(); |
| while (!replacementCanProceed) |
| Thread.yield(); |
| setter.setModel(model); |
| replacementThread = null; |
| } |
| |
| } |