Performance issue in Restlet - java

when I try to request a resource from my API via 100 threads at the same time (It's a simple performance test) I get the following server error message:
Unable to run the following server-side task: Handle inbound messages
I already searched the internet but couldn't find any hint how to get rid of it.
Any experience how to handle that error?
Greetingz,
Cooks
Edit:
Client:
public class PerformanceTest extends Thread {
static ClientResource client;
static int recCounter = 0;
public PerformanceTest(){
super();
}
public static void main(String[] args){
client = new ClientResource("http://localhost:8082/api/module/news/1");
ChallengeScheme scheme = ChallengeScheme.HTTP_BASIC;
ChallengeResponse authentication = new ChallengeResponse(scheme, "app+postapp", "");
client.setChallengeResponse(authentication);
for(int i = 0; i < 100; i++){
System.out.println("Starting test: " + i);
new PerformanceTest().start();
}
}
#Override
public void run() {
JsonRepresentation entity;
try {
entity = new JsonRepresentation(client.get());
recCounter++;
System.out.println("(" + getRecCounter() + ") result: " + entity.getJsonObject().toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private synchronized int getRecCounter(){
return recCounter;
}
Server:
This is my Application Class that starts the server:
public class MyApplication extends Application {
private DB db;
public MyApplication() {
db = new DB();
}
public static void main(String[] args) throws Exception {
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8082);
Application application = new MyApplication();
// Attach the application to the component with a defined contextroot
String contextRoot = "/api";
component.getDefaultHost().attach(contextRoot, application);
component.start();
}
public Restlet createInboundRoot() {
router.attach("/module/news", NewsResource.class);
router.attach("/module/news/{itemId}", NewsResource.class);
router.attach("/module/news/item", NewsResource.class);
router.attach("/module/news/item/{itemId}", NewsResource.class);
// Create Verifier
CredentialsVerifier verifier = new CredentialsVerifier(getDB());
// Create a Guard
ChallengeAuthenticator guard = new ChallengeAuthenticator(getContext(), ChallengeScheme.HTTP_BASIC, "app");
guard.setVerifier(verifier);
guard.setNext(router);
return guard;
}
public synchronized DB getDB() {
return this.db;
}
}

Related

How to add second activity in Amazon SWF hello_sample example

I've successfully implemented the simple Java Amazon SWF example called hello_sample. I created the ActivityWorker executable that polls SWF for activity tasks to process. I created the WorkflowWorker executable that polls SWF for decision tasks and I have a WorkflowStarter executable that kicks off the workflow execution. It works as advertised. What I don't understand is how do I configure and add a second activity to run after the first activity?
WorkflowWorker:
public class WorkflowWorker {
private static final AmazonSimpleWorkflow swf = AmazonSimpleWorkflowClientBuilder.defaultClient();
public static void main(String[] args) {
PollForDecisionTaskRequest task_request =
new PollForDecisionTaskRequest()
.withDomain(Constants.DOMAIN)
.withTaskList(new TaskList().withName(Constants.TASKLIST));
while (true) {
System.out.println(
"WorkflowWorker is polling for a decision task from the tasklist '" +
Constants.TASKLIST + "' in the domain '" +
Constants.DOMAIN + "'.");
DecisionTask task = swf.pollForDecisionTask(task_request);
String taskToken = task.getTaskToken();
if (taskToken != null) {
try {
executeDecisionTask(taskToken, task.getEvents());
}
catch (Throwable th) {
th.printStackTrace();
}
}
}
}
private static void executeDecisionTask(String taskToken, List<HistoryEvent> events) throws Throwable {
List<Decision> decisions = new ArrayList<Decision>();
String workflow_input = null;
int scheduled_activities = 0;
int open_activities = 0;
boolean activity_completed = false;
String result = null;
System.out.println("WorkflowWorker is executing the decision task for the history events: [");
for (HistoryEvent event : events) {
System.out.println(" " + event);
switch(event.getEventType()) {
case "WorkflowExecutionStarted":
workflow_input = event.getWorkflowExecutionStartedEventAttributes().getInput();
break;
case "ActivityTaskScheduled":
scheduled_activities++;
break;
case "ScheduleActivityTaskFailed":
scheduled_activities--;
break;
case "ActivityTaskStarted":
scheduled_activities--;
open_activities++;
break;
case "ActivityTaskCompleted":
open_activities--;
activity_completed = true;
result = event.getActivityTaskCompletedEventAttributes().getResult();
break;
case "ActivityTaskFailed":
open_activities--;
break;
case "ActivityTaskTimedOut":
open_activities--;
break;
}
}
System.out.println("]");
if (activity_completed) {
decisions.add(
new Decision()
.withDecisionType(DecisionType.CompleteWorkflowExecution)
.withCompleteWorkflowExecutionDecisionAttributes(
new CompleteWorkflowExecutionDecisionAttributes()
.withResult(result)));
}
else {
if (open_activities == 0 && scheduled_activities == 0) {
ScheduleActivityTaskDecisionAttributes attrs =
new ScheduleActivityTaskDecisionAttributes()
.withActivityType(new ActivityType()
.withName(Constants.ACTIVITY)
.withVersion(Constants.ACTIVITY_VERSION))
.withActivityId(UUID.randomUUID().toString())
.withInput(workflow_input);
decisions.add(
new Decision()
.withDecisionType(DecisionType.ScheduleActivityTask)
.withScheduleActivityTaskDecisionAttributes(attrs));
}
else {
// an instance of HelloActivity is already scheduled or running. Do nothing, another
// task will be scheduled once the activity completes, fails or times out
}
}
System.out.println("WorkflowWorker is exiting the decision task with the decisions " + decisions);
swf.respondDecisionTaskCompleted(
new RespondDecisionTaskCompletedRequest()
.withTaskToken(taskToken)
.withDecisions(decisions));
}
}
ActivityWorker:
public class ActivityWorker {
private static final AmazonSimpleWorkflow swf = AmazonSimpleWorkflowClientBuilder.defaultClient();
private static CountDownLatch waitForTermination = new CountDownLatch(1);
private static volatile boolean terminate = false;
private static String executeActivityTask(String g_species) throws Throwable {
String s = " ******** Hello, " + g_species + "!";
System.out.println(s);
String cwd = Paths.get(".").toAbsolutePath().normalize().toString();
String filename = "g_species.txt";
Path filePath = Paths.get(cwd, filename);
String filePathName = filePath.toString();
BufferedWriter output = null;
try {
File file = new File (filePathName);
output = new BufferedWriter(new FileWriter(file));
output.write(g_species);
}
catch (IOException e) {
e.printStackTrace();
}
finally {
if (output != null) {
output.close();
}
}
return g_species;
}
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
try {
terminate = true;
System.out.println("ActivityWorker is waiting for the current poll request to return before shutting down.");
waitForTermination.await(60, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
// ignore
System.out.println(e.getMessage());
}
}
});
try {
pollAndExecute();
}
finally {
waitForTermination.countDown();
}
}
public static void pollAndExecute() {
while (!terminate) {
System.out.println("ActivityWorker is polling for an activity task from the tasklist '"
+ Constants.TASKLIST + "' in the domain '" + Constants.DOMAIN + "'.");
ActivityTask task = swf.pollForActivityTask(new PollForActivityTaskRequest()
.withDomain(Constants.DOMAIN)
.withTaskList(new TaskList().withName(Constants.TASKLIST)));
String taskToken = task.getTaskToken();
if (taskToken != null) {
String result = null;
Throwable error = null;
try {
System.out.println("ActivityWorker is executing the activity task with input '" + task.getInput() + "'.");
result = executeActivityTask(task.getInput());
}
catch (Throwable th) {
error = th;
}
if (error == null) {
System.out.println("The activity task succeeded with result '" + result + "'.");
swf.respondActivityTaskCompleted(
new RespondActivityTaskCompletedRequest()
.withTaskToken(taskToken)
.withResult(result));
}
else {
System.out.println("The activity task failed with the error '"
+ error.getClass().getSimpleName() + "'.");
swf.respondActivityTaskFailed(
new RespondActivityTaskFailedRequest()
.withTaskToken(taskToken)
.withReason(error.getClass().getSimpleName())
.withDetails(error.getMessage()));
}
}
}
}
}
WorkflowStarter that kicks it all off:
public class WorkflowStarter {
private static final AmazonSimpleWorkflow swf = AmazonSimpleWorkflowClientBuilder.defaultClient();
public static final String WORKFLOW_EXECUTION = "HelloWorldWorkflowExecution";
public static void main(String[] args) {
String workflow_input = "Amazon SWF";
if (args.length > 0) {
workflow_input = args[0];
}
System.out.println("Starting the workflow execution '" + WORKFLOW_EXECUTION +
"' with input '" + workflow_input + "'.");
WorkflowType wf_type = new WorkflowType()
.withName(Constants.WORKFLOW)
.withVersion(Constants.WORKFLOW_VERSION);
Run run = swf.startWorkflowExecution(new StartWorkflowExecutionRequest()
.withDomain(Constants.DOMAIN)
.withWorkflowType(wf_type)
.withWorkflowId(WORKFLOW_EXECUTION)
.withInput(workflow_input)
.withExecutionStartToCloseTimeout("90"));
System.out.println("Workflow execution started with the run id '" +
run.getRunId() + "'.");
}
}
I would recommend to not reinvent the wheel and use the AWS Flow Framework for Java that is officially supported by Amazon. It already implements all the low level details and allows you to focus on a business logic of your workflow directly.
Here is an example worklow that uses three activities (taken from the developer guide).
Activities interface:
import com.amazonaws.services.simpleworkflow.flow.annotations.Activities;
import com.amazonaws.services.simpleworkflow.flow.annotations.ActivityRegistrationOptions;
#ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 300,
defaultTaskStartToCloseTimeoutSeconds = 10)
#Activities(version="1.0")
public interface GreeterActivities {
public String getName();
public String getGreeting(String name);
public void say(String what);
}
Activities implementation:
public class GreeterActivitiesImpl implements GreeterActivities {
#Override
public String getName() {
return "World";
}
#Override
public String getGreeting(String name) {
return "Hello " + name;
}
#Override
public void say(String what) {
System.out.println(what);
}
}
Workflow interface:
import com.amazonaws.services.simpleworkflow.flow.annotations.Execute;
import com.amazonaws.services.simpleworkflow.flow.annotations.Workflow;
import com.amazonaws.services.simpleworkflow.flow.annotations.WorkflowRegistrationOptions;
#Workflow
#WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 3600)
public interface GreeterWorkflow {
#Execute(version = "1.0")
public void greet();
}
Workflow implementation:
import com.amazonaws.services.simpleworkflow.flow.core.Promise;
public class GreeterWorkflowImpl implements GreeterWorkflow {
private GreeterActivitiesClient operations = new GreeterActivitiesClientImpl();
public void greet() {
Promise<String> name = operations.getName();
Promise<String> greeting = operations.getGreeting(name);
operations.say(greeting);
}
}
The worker that hosts both of them. Obviously it can be broken into separate activity and workflow workers:
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient;
import com.amazonaws.services.simpleworkflow.flow.ActivityWorker;
import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker;
public class GreeterWorker {
public static void main(String[] args) throws Exception {
ClientConfiguration config = new ClientConfiguration().withSocketTimeout(70*1000);
String swfAccessId = System.getenv("AWS_ACCESS_KEY_ID");
String swfSecretKey = System.getenv("AWS_SECRET_KEY");
AWSCredentials awsCredentials = new BasicAWSCredentials(swfAccessId, swfSecretKey);
AmazonSimpleWorkflow service = new AmazonSimpleWorkflowClient(awsCredentials, config);
service.setEndpoint("https://swf.us-east-1.amazonaws.com");
String domain = "helloWorldWalkthrough";
String taskListToPoll = "HelloWorldList";
ActivityWorker aw = new ActivityWorker(service, domain, taskListToPoll);
aw.addActivitiesImplementation(new GreeterActivitiesImpl());
aw.start();
WorkflowWorker wfw = new WorkflowWorker(service, domain, taskListToPoll);
wfw.addWorkflowImplementationType(GreeterWorkflowImpl.class);
wfw.start();
}
}
The workflow starter:
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient;
public class GreeterMain {
public static void main(String[] args) throws Exception {
ClientConfiguration config = new ClientConfiguration().withSocketTimeout(70*1000);
String swfAccessId = System.getenv("AWS_ACCESS_KEY_ID");
String swfSecretKey = System.getenv("AWS_SECRET_KEY");
AWSCredentials awsCredentials = new BasicAWSCredentials(swfAccessId, swfSecretKey);
AmazonSimpleWorkflow service = new AmazonSimpleWorkflowClient(awsCredentials, config);
service.setEndpoint("https://swf.us-east-1.amazonaws.com");
String domain = "helloWorldWalkthrough";
GreeterWorkflowClientExternalFactory factory = new GreeterWorkflowClientExternalFactoryImpl(service, domain);
GreeterWorkflowClientExternal greeter = factory.getClient("someID");
greeter.greet();
}
}

servlet not working in CouchBase server

IN order to test couchbase, I am trying to create 30K-specific documents in 15 minutes.
During the test, 6563 documents are created and then hangs. I have seen that it takes 2 minutes to create 0-3K thousand; 5 minutes to create between 3K-6K; and 5 minutes to create the final 6K -6.5K documents.
Example here.
I would appreciate help in understanding what I am doing wrong. The code is below:
public class ConnectionManager {
Logger logger = Logger.getLogger(getClass().getName());
private CouchbaseClient client;
public ConnectionManager() {
init();
}
public void init() {
try {
logger.info("Opening base connection.");
List<URI> hosts = Arrays.asList(new URI("http://127.0.0.1:8091/pools"));
String bucket = "default";
String password = "";
client = new CouchbaseClient(hosts, bucket, password);
} catch (Exception e) {
client = null;
throw new IllegalStateException(e);
}
}
#PreDestroy
public void destroy() {
logger.info("Closing base connection.");
if (client != null) {
client.shutdown();
client = null;
}
}
public CouchbaseClient getClient() {
return client;
}
}
public class DatabaseManager {
ConnectionManager cm;
public DatabaseManager() {
cm = new ConnectionManager();
}
public String addDocument(String result) {
CouchbaseClient c = cm.getClient();
JSONParameters j = new JSONParameters();
String id = UUID.randomUUID().toString();
Date today = new Date();
SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss.SSSZ");
String date = DATE_FORMAT.format(today);
j.setTime(date);
j.setData(UUID.randomUUID().toString());
j.setSender_id(result);
j.setFlag(false);
Gson gson = new Gson();
String json = gson.toJson(j);
c.add(result, json);
return json;
}
public class DataBaseAddServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
for (int k = 0; k < 30000; k++) {
String id = UUID.randomUUID().toString();
DatabaseManager dbManager = new DatabaseManager();
dbManager.addDocument(id);
}
} catch (Exception e) {
resp.getOutputStream().println(e.getMessage());
resp.flushBuffer();
}
}
}
I think you missed a key point from the example you linked to: in the Servlet, DatabaseManager is injected via dependency injection and thus there's only one instance created.
In you code, you actually create a new DatabaseManager inside the loop, so you end up creating 30K CouchbaseClients. You are probably hitting a limit, and definitely wasting a lot of time and resources with that much extra clients.
Just moving the DatabaseManager dbManager = new DatabaseManager(); before the for loop should make things far better.

playframework-2.3 Akka-Async interaction porting?

I have some old playframework 2.2 java webservice that interacts with akka, and now I should port them to playframework 2.3.
However, async has been deprecated and even after reading the doc about the async porting (http://www.playframework.com/documentation/2.3.x/JavaAsync) I wasn't able to understand how to apply it to my case (code below):
I must make the await for a timeout/akka server reply before starting the construction of my reply (ok()), otherwise I will block the thread.
I should make the actorselection async too.
I should make the akka server reply parsing/reply construction async too
I looked around and I wasn't able to find an example of such interactions, even in typesafe templates.
How could I do that?
/* playframework 2.2 code */
public class Resolve extends Controller {
private final static String RESOLVER_ACTOR = play.Play.application().configuration().getString("actor.resolve");
#CorsRest
#VerboseRest
#RequireAuthentication
#BodyParser.Of(BodyParser.Json.class)
public static Result getJsonTree() {
JsonNode json = request().body().asJson();
ProtoBufMessages.ResolveRequest msg;
ResolveRequestInput input;
try {
input = new ResolveRequestInput(json);
} catch (rest.exceptions.MalformedInputException mie) {
return badRequest(mie.getMessage());
}
msg = ((ProtoBufMessages.ResolveRequest)input.getMessage());
ActorSelection resolver = Akka.system().actorSelection(RESOLVER_ACTOR);
Timeout tim = new Timeout(Duration.create(4, "seconds"));
Future<Object> fut = Patterns.ask(resolver, input.getMessage(), tim);
return async (
F.Promise.wrap(fut).map(
new F.Function<Object, Result>() {
public Result apply(Object response) {
ProtoBufMessages.ResolveReply rsp = ((ProtoBufMessages.ResolveReply)response);
ResolveOutput output = new ResolveOutput(rsp);
return ok(output.getJsonReply());
}
}
)
);
}
}
I came out with the code below
public class Resolve extends Controller {
private final static String RESOLVER_ACTOR = play.Play.application().configuration().getString("actor.resolve");
private final static BrainProtoMessages.ResolveReply request_error = BrainProtoMessages.ResolveReply.newBuilder()
.setReturnCode(BResults.REQUEST_FAILED)
.build();
#CorsRest
#VerboseRest
#RequireAuthentication
#BodyParser.Of(BodyParser.Json.class)
public static Result resolve_map() {
final ResolveRequestInput input;
final F.Promise<ActorSelection> selected_target;
final F.Promise<Future<Object>> backend_request;
final F.Promise<BrainProtoMessages.ResolveReply> backend_reply;
final F.Promise<ObjectNode> decode_json;
final F.Promise<Result> ok_result;
final JsonNode json = request().body().asJson();
try {
input = new ResolveRequestInput(json);
} catch (rest.exceptions.MalformedInputException mie) {
return badRequest(mie.getMessage());
}
selected_target = F.Promise.promise(
new F.Function0<ActorSelection>() {
#Override
public ActorSelection apply() throws Throwable {
return Akka.system().actorSelection(RESOLVER_ACTOR);
}
}
);
backend_request =
selected_target.map(
new F.Function<ActorSelection, Future<Object>>() {
#Override
public Future<Object> apply(ActorSelection actorSelection) throws Throwable {
return Patterns.ask(actorSelection, input.getMessage(),new Timeout(Duration.create(4, "seconds")));
}
}
);
backend_reply = backend_request.map(
new F.Function<Future<Object>, BrainProtoMessages.ResolveReply>() {
#Override
public BrainProtoMessages.ResolveReply apply(Future<Object> akka_reply) throws Throwable {
try {
return (BrainProtoMessages.ResolveReply) Await.result(akka_reply, Duration.create(4, "seconds"));
}catch(Exception error)
{
return request_error;
}
}
}
);
decode_json = backend_reply.map(
new F.Function<BrainProtoMessages.ResolveReply, ObjectNode>() {
#Override
public ObjectNode apply(BrainProtoMessages.ResolveReply response) throws Throwable {
return new ResolveOutput(response).getJsonReply();
}
}
);
ok_result = decode_json.map(
new F.Function<ObjectNode, Result>() {
#Override
public Result apply(ObjectNode reply) {
return ok(reply);
}
}
);
try {
return ok_result.get(8000);
}catch(Exception error)
{
return internalServerError();
}
}
}

Excel 2013 error OData4J JPAProducer odata feed

I have created a very basic producer example using OData4J (JPAProducer)
Now I can see the info about schema on browser normal.
However the excel 2013 data connection wizard showing error.
I tried Excel with http://services.odata.org/V3/OData/OData.svc/
worked fine.
What am I doing wrong.
Any help would be greatly appreciated.
public static JPAProducer createProducer() {
Map properties = new HashMap();
properties.put(PersistenceUnitProperties.NON_JTA_DATASOURCE, DatabaseUtil.getDataSource());
javax.persistence.EntityManagerFactory factory = Persistence.createEntityManagerFactory("persistentunit",
properties);
JPAProducer producer = new JPAProducer(factory, "", 50);
return producer;
}
public static void startService() {
DefaultODataProducerProvider.setInstance(createProducer());
hostODataServer("http://localhost:8887/JPAProducerExample.svc/");
}
public static void main(String[] args) {
startService();
}
private static void hostODataServer(String baseUri) {
ODataServer server = null;
try {
server = startODataServer(baseUri);
} catch (Exception e) {
System.out.print(e.getLocalizedMessage());
}
}
private static ODataServer startODataServer(String baseUri) {
return createODataServer(baseUri).start();
}
private static ODataServer createODataServer(String baseUri) {
return new ODataJerseyServer(baseUri, ODataApplication.class, RootApplication.class);
}

How to run a long running processor async and use it from same thread?

Basically, we have a class called OfficeManger which acts as a driver to connect to openoffice software, it needs to be connected all the time so we can use the converter to convert documents. We start the OpenOfficeProcess during the start of the web application, which starts fine. But looks like the executor which running in init() is on different thread and we couldn't able to get the running instance of OfficeManager. How to run in its own thread so that I can have this instance called from different class to use the converter method?
OfficeDocumentConverter converter = OpenOfficeProcessor.getInstance().getDocumentConverter();
converter.convert(inputFile, outputFile, pdf);
OpenOfficeProcessor
public class OpenOfficeProcessor {
private static final OpenOfficeProcessor INSTANCE = new OpenOfficeProcessor();
static ExecutorService executor = Executors.newSingleThreadExecutor();
private final OfficeManager officeManager;
private final OfficeDocumentConverter documentConverter;
public OpenOfficeProcessor(){
DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();
String homePath = ConfigurationManager.getApplicationProperty(ConfigurationManager.OPENOFFICE_HOME_PATH);
if(homePath != null){
configuration.setOfficeHome(homePath);
} else {
LOG.error("OpenOffice.home.path is not set in the properties file");
new Throwable("Please set OPENOFFICE.HOME.PATH parameter in the properties file");
}
String port = ConfigurationManager.getApplicationProperty(ConfigurationManager.OPENOFFICE_LISTENER_PORT);
if( port != null){
configuration.setPortNumber(Integer.parseInt(port));
}else {
LOG.error("openoffice.listener.port is not set in the properties file");
}
String executionTimeout = ConfigurationManager.getApplicationProperty(ConfigurationManager.OPENOFFICE_EXECUTION_TIMEOUT);
if(executionTimeout != null){
configuration.setTaskExecutionTimeout(Long.parseLong(executionTimeout));
}
String pipeNames = ConfigurationManager.getApplicationProperty(ConfigurationManager.OPENOFFICE_PIPES_NAMES);
if(ConfigurationManager.getApplicationProperty(ConfigurationManager.OPENOFFICE_PIPES_NAMES)!= null){
configuration.setPipeNames(pipeNames);
}
officeManager = configuration.buildOfficeManager();
documentConverter = new OfficeDocumentConverter(officeManager);
}
public static OpenOfficeProcessor getInstance()
{
return INSTANCE;
}
protected static void init() {
LOG.debug("Starting the open office listener...");
executor.submit(new Callable(){
#Override
public Object call() throws Exception {
OpenOfficeProcessor.getInstance().officeManager.start();
return null;
}
});
}
protected static void destroy() {
LOG.debug("Stopping the open office listener...");
OpenOfficeProcessor.getInstance().officeManager.stop();
}
public OfficeManager getOfficeManager() {
return officeManager;
}
public OfficeDocumentConverter getDocumentConverter() {
return documentConverter;
}
}
OfficeManager
public interface OfficeManager {
void execute(OfficeTask task) throws OfficeException;
void start() throws OfficeException;
void stop() throws OfficeException;
boolean isRunning();
}

Categories

Resources