Corda responder flow not answering - token

I created a very easy flow test with IntelliJ.
#Test
public void dummyTest() throws InterruptedException, ExecutionException {
Party Alice = aliceNode.getServices().getIdentityService().wellKnownPartyFromX500Name(new CordaX500Name("Alice", "London", "GB"));
FlowInitiatorIssueToken flow = new FlowInitiatorIssueToken(30, alice, network.getDefaultNotaryIdentity());
SignedTransaction transaction = bobNode.startFlow(flow).get();
// The error occurs because of this line ....
State state = (State) transaction.getTx().getOutputStates().get(0);
assertEquals(state.getParticipants(), alice);
VaultQueryCriteria criteria = new VaultQueryCriteria(Vault.StateStatus.ALL);
aliceNode.transaction(() -> {
Vault.Page<State> result = aliceNode.getServices().getVaultService().queryBy(State.class, criteria);
assertTrue(result.getStates().size() > 0);
return null;
});
network.runNetwork();
}
IntelliJ is not able to fulfil the test and gives me the error
statemachine.FlowMonitor. - Flow with id 3982ab19-3e5b-4737-9adf-e4a6a97d20e6 has been waiting for 117 seconds to receive messages from parties [O=Alice, L=London, C=GB]
This led to the assumption that the responder flow is not doing anything.
// ******************
// * Initiator flow *
// ******************
#InitiatingFlow
#StartableByRPC
public class FlowInitiatorIssueToken extends FlowLogic<SignedTransaction> {
private final Integer value;
private final Party counterParty;
private final Party notary;
public FlowInitiatorIssuToken(Integer value, Party counterParty, Party notary) {
this.value = value;
this.counterParty = counterParty;
this.notary = notary;
}
/**
* The flow logic is encapsulated within the call() method.
*/
#Suspendable
#Override
public SignedTransaction call() throws FlowException {
/*------------------------------
* SENDING AND RECEIVING DATA *
------------------------------*/
FlowSession issueTokenSession = initiateFlow((Party) counterParty);
/*------------------------------------------
* GATHERING OTHER TRANSACTION COMPONENTS *
------------------------------------------*/
State outputState = new State(this.value, this.counterParty);
Command<ContractToken.Commands.Issue> command = new Command<>(new ContractToken.Commands.Issue(), getOurIdentity().getOwningKey());
/*------------------------
* TRANSACTION BUILDING *
------------------------*/
TransactionBuilder txBuilder = new TransactionBuilder(notary)
.addOutputState(outputState, ContractToken.ID)
.addCommand(command);
/*-----------------------
* TRANSACTION SIGNING *
-----------------------*/
SignedTransaction signedTx = getServiceHub().signInitialTransaction(txBuilder);
/*------------------------------
* FINALISING THE TRANSACTION *
------------------------------*/
System.out.println("Hey World!");
subFlow(new FinalityFlow(signedTx, issueTokenSession));
return null;
}
}
// ******************
// * Responder flow *
// ******************
#InitiatedBy(FlowInitiatorIssueToken.class)
public class FlowResponderIssueToken extends FlowLogic<SignedTransaction> {
private final FlowSession issueTokenSession;
public FlowResponderIssueToken(FlowSession issueTokenSession) {
this.issueTokenSession = issueTokenSession;
}
#Suspendable
#Override
public SignedTransaction call() throws FlowException {
/*-----------------------------------------
* RESPONDING TO COLLECT_SIGNATURES_FLOW *
-----------------------------------------*/
class SignTxFlow extends SignTransactionFlow {
private SignTxFlow(FlowSession issueTokenSession) {
super(issueTokenSession);
}
#Override
protected void checkTransaction(SignedTransaction stx) {
}
}
SecureHash idOfTxWeSigned = subFlow(new SignTxFlow(issueTokenSession, SignTransactionFlow.tracker())).getId();
/*------------------------------
* FINALISING THE TRANSACTION *
------------------------------*/
subFlow(new ReceiveFinalityFlow(issueTokenSession, idOfTxWeSigned));
return null;
}
}
The initiator flow is executed. I can see that, because the System.out.println("Hey World!") command is showing up in the logs. However, I don't know whether the responder flow is never started by the initiator flow or it is just not reacting. Maybe you can help me with that.
Thanks!

You didn't call CollectSignaturesFlow in your initiator; that's why you didn't initiate a "conversation" with the responder for them to sign the transaction. See example here.
SignTransactionFlow that you call in your responder is a "reply" to calling CollectSignaturesFlow in the initiator.
Btw, you must verify a transaction before you sign it in your initiator. See example here.

Another thing missing was the key of the counterParty. When initialising the command, I added
final Command<ContractToken.Commands.Issue> txCommand = new Command<>(
new ContractToken.Commands.Issue(),
ImmutableList.of(getOurIdentity().getOwningKey(), counterParty.getOwningKey()));

Related

Rate limiting based on user plan in Spring Cloud Gateway

Say my users subscribe to a plan. Is it possible then using Spring Cloud Gateway to rate limit user requests based up on the subscription plan? Given there're Silver and Gold plans, would it let Silver subscriptions to have replenishRate/burstCapacity of 5/10 and Gold 50/100?
I naively thought of passing a new instance of RedisRateLimiter (see below I construct a new one with 5/10 settings) to the filter but I needed to get the information about the user from the request somehow in order to be able to find out whether it is Silver and Gold plan.
#Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route(p -> p
.path("/get")
.filters(f ->
f.requestRateLimiter(r -> {
r.setRateLimiter(new RedisRateLimiter(5, 10))
})
.uri("http://httpbin.org:80"))
.build();
}
Am I trying to achieve something that is even possible with Spring Cloud Gateway? What other products would you recommend to check for the purpose if any?
Thanks!
Okay, it is possible by creating a custom rate limiter on top of RedisRateLimiter class. Unfortunately the class has not been architected for extendability so the solution is somewhat "hacky", I could only decorate the normal RedisRateLimiter and duplicate some of its code in there:
#Primary
#Component
public class ApiKeyRateLimiter implements RateLimiter {
private Log log = LogFactory.getLog(getClass());
// How many requests per second do you want a user to be allowed to do?
private static final int REPLENISH_RATE = 1;
// How much bursting do you want to allow?
private static final int BURST_CAPACITY = 1;
private final RedisRateLimiter rateLimiter;
private final RedisScript<List<Long>> script;
private final ReactiveRedisTemplate<String, String> redisTemplate;
#Autowired
public ApiKeyRateLimiter(
RedisRateLimiter rateLimiter,
#Qualifier(RedisRateLimiter.REDIS_SCRIPT_NAME) RedisScript<List<Long>> script,
ReactiveRedisTemplate<String, String> redisTemplate) {
this.rateLimiter = rateLimiter;
this.script = script;
this.redisTemplate = redisTemplate;
}
// These two methods are the core of the rate limiter
// Their purpose is to come up with a rate limits for given API KEY (or user ID)
// It is up to implementor to return limits based up on the api key passed
private int getBurstCapacity(String routeId, String apiKey) {
return BURST_CAPACITY;
}
private int getReplenishRate(String routeId, String apiKey) {
return REPLENISH_RATE;
}
public Mono<Response> isAllowed(String routeId, String apiKey) {
int replenishRate = getReplenishRate(routeId, apiKey);
int burstCapacity = getBurstCapacity(routeId, apiKey);
try {
List<String> keys = getKeys(apiKey);
// The arguments to the LUA script. time() returns unixtime in seconds.
List<String> scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "",
Instant.now().getEpochSecond() + "", "1");
Flux<List<Long>> flux = this.redisTemplate.execute(this.script, keys, scriptArgs);
return flux.onErrorResume(throwable -> Flux.just(Arrays.asList(1L, -1L)))
.reduce(new ArrayList<Long>(), (longs, l) -> {
longs.addAll(l);
return longs;
}) .map(results -> {
boolean allowed = results.get(0) == 1L;
Long tokensLeft = results.get(1);
Response response = new Response(allowed, getHeaders(tokensLeft, replenishRate, burstCapacity));
if (log.isDebugEnabled()) {
log.debug("response: " + response);
}
return response;
});
}
catch (Exception e) {
/*
* We don't want a hard dependency on Redis to allow traffic. Make sure to set
* an alert so you know if this is happening too much. Stripe's observed
* failure rate is 0.01%.
*/
log.error("Error determining if user allowed from redis", e);
}
return Mono.just(new Response(true, getHeaders(-1L, replenishRate, burstCapacity)));
}
private static List<String> getKeys(String id) {
String prefix = "request_rate_limiter.{" + id;
String tokenKey = prefix + "}.tokens";
String timestampKey = prefix + "}.timestamp";
return Arrays.asList(tokenKey, timestampKey);
}
private HashMap<String, String> getHeaders(Long tokensLeft, Long replenish, Long burst) {
HashMap<String, String> headers = new HashMap<>();
headers.put(RedisRateLimiter.REMAINING_HEADER, tokensLeft.toString());
headers.put(RedisRateLimiter.REPLENISH_RATE_HEADER, replenish.toString());
headers.put(RedisRateLimiter.BURST_CAPACITY_HEADER, burst.toString());
return headers;
}
#Override
public Map getConfig() {
return rateLimiter.getConfig();
}
#Override
public Class getConfigClass() {
return rateLimiter.getConfigClass();
}
#Override
public Object newConfig() {
return rateLimiter.newConfig();
}
}
So, the route would look like this:
#Component
public class Routes {
#Autowired
ApiKeyRateLimiter rateLimiter;
#Autowired
ApiKeyResolver apiKeyResolver;
#Bean
public RouteLocator theRoutes(RouteLocatorBuilder b) {
return b.routes()
.route(p -> p
.path("/unlimited")
.uri("http://httpbin.org:80/anything?route=unlimited")
)
.route(p -> p
.path("/limited")
.filters(f ->
f.requestRateLimiter(r -> {
r.setKeyResolver(apiKeyResolver);
r.setRateLimiter(rateLimiter);
} )
)
.uri("http://httpbin.org:80/anything?route=limited")
)
.build();
}
}
Hope it saves a work day for somebody...

SimpleRabbitListenerContainerFactory and defaultRequeueRejected

As per doc, defaultRequeueRejected's default value is true, but looking at code it seems its false. I am not sure if I am missing anything or we have to change that in SimpleRabbitListenerContainerFactory.java
EDIT
Sample code, after putting message in test queue, I expect it to stay in queue since its failing but it is throwing it out. I want message to be retried so I configured that in container factory if it fails after retry I want it to be back in queue. I am sure I am missing understanding here.
#SpringBootApplication
public class MsgRequeExampleApplication {
public static void main(String[] args) {
SpringApplication.run(MsgRequeExampleApplication.class, args);
}
#Bean(name = "myContainerFactory")
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(new Jackson2JsonMessageConverter());
factory.setMissingQueuesFatal(false);
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(500);
factory.setAdviceChain(new Advice[] { org.springframework.amqp.rabbit.config.RetryInterceptorBuilder.stateless()
.maxAttempts(2).backOffPolicy(backOffPolicy).build() });
return factory;
}
#RabbitListener(queues = "test", containerFactory = "myContainerFactory")
public void processAdvisory(Message message) throws MyBusinessException {
try{
//Simulating exception while processing message
String nullString=null;
nullString.length();
}catch(Exception ex){
throw new MyBusinessException(ex.getMessage());
}
}
public class MyBusinessException extends Exception {
public MyBusinessException(String msg) {
super(msg);
}
}
}
There is a good description in the SimpleMessageListenerContainer JavaDocs:
/**
* Set the default behavior when a message is rejected, for example because the listener
* threw an exception. When true, messages will be requeued, when false, they will not. For
* versions of Rabbit that support dead-lettering, the message must not be requeued in order
* to be sent to the dead letter exchange. Setting to false causes all rejections to not
* be requeued. When true, the default can be overridden by the listener throwing an
* {#link AmqpRejectAndDontRequeueException}. Default true.
* #param defaultRequeueRejected true to reject by default.
*/
public void setDefaultRequeueRejected(boolean defaultRequeueRejected) {
this.defaultRequeueRejected = defaultRequeueRejected;
}
Does it make sense to you?
UPDATE
To requeue after retry exhausting you need to configure some custom MessageRecoverer on the RetryInterceptorBuilder with the code like:
.recoverer((message, cause) -> {
ReflectionUtils.rethrowRuntimeException(cause);
})
This way the exception will be thrown to the listener container and according its defaultRequeueRejected the message will be requeued or not.

Groovy/Grails promises/futures. There is no .resolve(1,2,3) method. Strange?

I am developing in a Grails application. What I want to do is to lock the request/response, create a promise, and let someone else resolve it, that is somewhere else in the code, and then flush the response.
What I find really strange is that the Promise promise = task {} interface has no method that resembles resolve or similar.
I need to lock the response until someone resolves the promise, which is a global/static property set in development mode.
Promise interface:
http://grails.org/doc/latest/api/grails/async/Promise.html
I have looked at the GPars doc and can't find anything there that resembles a resolve method.
How can I create a promise, that locks the response or request, and then flushes the response when someone resolves it?
You can call get() on the promise which will block until whatever the task is doing completes, but I imagine what that is not what you want. What you want seems to be equivalent to a GPars DataflowVariable:
http://gpars.org/1.0.0/javadoc/groovyx/gpars/dataflow/DataflowVariable.html
Which allows using the left shift operator to resolve the value from another thread. Currently there is no way to use the left shift operator via Grails directly, but since Grails' promise API is just a layer over GPars this can probably be accomplished by using the GPars API directly with something like:
import org.grails.async.factory.gpars.*
import groovyx.gpars.dataflow.*
import static grails.async.Promise.*
def myAction() {
def dataflowVar = new DataflowVariable()
task {
// do some calculation and resolve data flow variable
def expensiveData = ...
dataflowVar << expensiveData
}
return new GParsPromise(dataflowVar)
}
It took me quite some time to get around this and have a working answer.
I must say that it appears as if Grails is quite a long way of making this work properly.
task { }
will always execute immediatly, so the call is not put on hold until dispatch() or whatever is invoked which is a problem.
Try this to see:
public def test() {
def dataflowVar = new groovyx.gpars.dataflow.DataflowVariable()
task {
// do some calculation and resolve data flow variable
println '1111111111111111111111111111111111111111111111111111'
//dataflowVar << expensiveData
}
return new org.grails.async.factory.gpars.GparsPromise(dataflowVar);
}
If you are wondering what this is for, it is to make the lesscss refresh automatically in grails, which is a problem when you are using import statements in less. When the file is touched, the lesscss compiler will trigger a recompilation, and only when it is done should it respond to the client.
On the client side I have some javascript that keeps replacing the last using the refresh action here:
In my controller:
/**
* Refreshes link resources. refresh?uri=/resource/in/web-app/such/as/empty.less
*/
public def refresh() {
return LessRefresh.stackRequest(request, params.uri);
}
A class written for this:
import grails.util.Environment
import grails.util.Holders
import javax.servlet.AsyncContext
import javax.servlet.AsyncEvent
import javax.servlet.AsyncListener
import javax.servlet.http.HttpServletRequest
/**
* #Author SecretService
*/
class LessRefresh {
static final Map<String, LessRefresh> FILES = new LinkedHashMap<String, LessRefresh>();
String file;
Boolean touched
List<AsyncContext> asyncContexts = new ArrayList<AsyncContext>();
String text;
public LessRefresh(String file) {
this.file = file;
}
/** Each request will be put on hold in a stack until dispatchAll below is called when the recompilation of the less file finished **/
public static AsyncContext stackRequest(HttpServletRequest request, String file) {
if ( !LessRefresh.FILES[file] ) {
LessRefresh.FILES[file] = new LessRefresh(file);
}
return LessRefresh.FILES[file].handleRequest(request);
}
public AsyncContext handleRequest(HttpServletRequest request) {
if ( Environment.current == Environment.DEVELOPMENT ) {
// We only touch it once since we are still waiting for the less compiler to finish from previous edits and recompilation
if ( !touched ) {
touched = true
touchFile(file);
}
AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(10000)
asyncContexts.add (asyncContext);
asyncContext.addListener(new AsyncListener() {
#Override
void onComplete(AsyncEvent event) throws IOException {
event.getSuppliedResponse().writer << text;
}
#Override
void onTimeout(AsyncEvent event) throws IOException {
}
#Override
void onError(AsyncEvent event) throws IOException {
}
#Override
void onStartAsync(AsyncEvent event) throws IOException {
}
});
return asyncContext;
}
return null;
}
/** When recompilation is done, dispatchAll is called from LesscssResourceMapper.groovy **/
public void dispatchAll(String text) {
this.text = text;
if ( asyncContexts ) {
// Process all
while ( asyncContexts.size() ) {
AsyncContext asyncContext = asyncContexts.remove(0);
asyncContext.dispatch();
}
}
touched = false;
}
/** A touch of the lessfile will trigger a recompilation **/
int count = 0;
void touchFile(String uri) {
if ( Environment.current == Environment.DEVELOPMENT ) {
File file = getWebappFile(uri);
if (file && file.exists() ) {
++count;
if ( count < 5000 ) {
file << ' ';
}
else {
count = 0
file.write( file.getText().trim() )
}
}
}
}
static File getWebappFile(String uri) {
new File( Holders.getServletContext().getRealPath( uri ) )
}
}
In LesscssResourceMapper.groovy of the lesscsss-recources plugin:
...
try {
lessCompiler.compile input, target
// Update mapping entry
// We need to reference the new css file from now on
resource.processedFile = target
// Not sure if i really need these
resource.sourceUrlExtension = 'css'
resource.contentType = 'text/css'
resource.tagAttributes?.rel = 'stylesheet'
resource.updateActualUrlFromProcessedFile()
// ==========================================
// Call made here!
// ==========================================
LessRefresh.FILES[resource.sourceUrl.toString()]?.dispatchAll( target.getText() );
} catch (LessException e) {
log.error("error compiling less file: ${originalFile}", e)
}
...
In the index.gsp file:
<g:set var="uri" value="${"${App.files.root}App/styles/empty.less"}"/>
<link media="screen, projection" rel="stylesheet" type="text/css" href="${r.resource(uri:uri)}" refresh="${g.createLink(controller:'home', action:'refresh', params:[uri:uri])}" resource="true">
JavaScript method refreshResources to replace the previous link href=...
/**
* Should only be used in development mode
*/
function refreshResources(o) {
o || (o = {});
var timeoutBegin = o.timeoutBegin || 1000;
var intervalRefresh = o.intervalRefresh || 1000;
var timeoutBlinkAvoid = o.timeoutBlinkAvoid || 400 ;
var maxErrors = o.maxErrors || 200 ;
var xpath = 'link[resource][type="text/css"]';
// Find all link[resource]
$(xpath).each(function(i, element) {
refresh( $(element) );
});
function refresh(element) {
var parent = element.parent();
var next = element.next();
var outer = element.clone().attr('href', '').wrap('<p>').parent().html();
var uri = element.attr('refresh');
var errorCount = 0;
function replaceLink() {
var link = $(outer);
link.load(function () {
// The link has been successfully added! Now remove the other ones, then do again
errorCount = 0;
// setTimeout needed to avoid blinking, we allow duplicates for a few milliseconds
setTimeout(function() {
var links = parent.find(xpath + '[refresh="'+uri+'"]');
var i = 0;
// Remove all but this one
while ( i < links.length - 1 ) {
links[i++].remove();
}
replaceLinkTimeout();
}, timeoutBlinkAvoid );
});
link.error(function(event, handler) {
console.log('Error refreshing: ' + outer );
++errorCount;
if ( errorCount < maxErrors ) {
// Load error, it happens. Remove this & redo!
link.remove();
replaceLink();
}
else {
console.log('Refresh: Aborting!')
}
});
link.attr('href', urlRandom(uri)).get(0);
link.insertBefore(next); // Insert just after
}
function urlRandom(uri) {
return uri + "&rand=" + Math.random();
}
function replaceLinkTimeout() {
setTimeout(function() {
replaceLink();
}, intervalRefresh ) ;
}
// Waith 1s before triggering the interval
setTimeout(function() {
replaceLinkTimeout();
}, timeoutBegin);
}
};
Comments
I am unsure why Javascript style promises have not been added to the Grails stack.
You can not render or stuff like that in the onComplete. render, redirect and what not are not available.
Something tells me that Grails and Promises/Futures are not there yet. The design of the GPars libraries seems not take into account of the core features which is to resolve later. At least it is not simple to do so.
It would be great if the dispatch() method actually could be invoked with some paramaters to pass from the resolving context. I am able to go around this using static properties.
I might continue to write my own solution and possibly contribute with a more fitting solutions around the AsyncContext class, but for now, this is enough for me.
I just wanted to refresh my less resources automatically.
Phew...
EDIT:
I made it to support several number of files. It is complete now!

App Error 104 uncaught : runtime exception while running blackberry application

I have created one application to get My location coordinates using GPS after deploying my code in simulator i am getting above error with explanation -
uncaught exception:pushmodalscreen called by a non-event thread
I am not able to figure out whats going wrong.
/**
* GPSDemo.java
*
* Copyright © 1998-2011 Research In Motion Ltd.
*
* Note: For the sake of simplicity, this sample application may not leverage
* resource bundles and resource strings. However, it is STRONGLY recommended
* that application developers make use of the localization features available
* within the BlackBerry development platform to ensure a seamless application
* experience across a variety of languages and geographies. For more information
* on localizing your application, please refer to the BlackBerry Java Development
* Environment Development Guide associated with this release.
*/
package com.gps;
import java.util.*;
import javax.microedition.location.*;
import net.rim.device.api.command.*;
import net.rim.device.api.gps.*;
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.util.*;
import net.rim.blackberry.api.invoke.*;
import net.rim.blackberry.api.maps.*;
import net.rim.blackberry.api.menuitem.*;
/**
* This application acts as a simple travel computer, recording route
* coordinates, speed and altitude. Recording begins as soon as the
* application is invoked.
*/
public class GPSScreen extends UiApplication
{
// Represents the number of updates over which altitude is calculated, in seconds
private static final int GRADE_INTERVAL = 5;
private static final long ID = 0x5d459971bb15ae7aL;
// Represents period of the position query, in seconds
private static int _interval = 1;
private double _latitude;
private double _longitude;
private LocationProvider _locationProvider;
private GPSDemoScreen _screen;
private MapView _mapview = new MapView();
/**
* Entry point for application
*
* #param args Command line arguments (not used)
*/
public static void main(String[] args)
{
// Create a new instance of the application and make the currently
// running thread the application's event dispatch thread.
new GPSScreen().enterEventDispatcher();
}
/**
* Create a new GPSDemo object
*/
public GPSScreen()
{
_screen = new GPSDemoScreen();
_screen.setTitle("GPS Demo");
// Attempt to start the location listening thread
if(startLocationUpdate())
{
_screen.setState(_locationProvider.getState());
}
// Render the screen
pushScreen(_screen);
}
/**
* Invokes the Location API with Standalone criteria
*
* #return True if the <code>LocationProvider</code> was successfully started, false otherwise
*/
private boolean startLocationUpdate()
{
boolean returnValue = false;
if(!(GPSInfo.getDefaultGPSMode() == GPSInfo.GPS_MODE_NONE))
{
try
{
Criteria criteria = new Criteria();
criteria.setCostAllowed(false);
_locationProvider = LocationProvider.getInstance(criteria);
if(_locationProvider != null)
{
/*
* Only a single listener can be associated with a provider,
* and unsetting it involves the same call but with null.
* Therefore, there is no need to cache the listener
* instance request an update every second.
*/
_locationProvider.setLocationListener(new LocationListenerImpl(), _interval, -1, -1);
returnValue = true;
}
else
{
invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("Failed to obtain a location provider, exiting...");
System.exit(0);
}
});
}
}
catch(final LocationException le)
{
invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("Failed to instantiate LocationProvider object, exiting..." + le.toString());
System.exit(0);
}
});
}
}
else
{
invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("GPS is not supported on this device, exiting...");
System.exit(0);
}
});
}
return true;
}
/**
* Implementation of the LocationListener interface. Listens for updates to
* the device location and displays the results.
*/
private class LocationListenerImpl implements LocationListener
{
/**
* #see javax.microedition.location.LocationListener#locationUpdated(LocationProvider,Location)
*/
public void locationUpdated(LocationProvider provider, Location location)
{
if(location.isValid())
{
_longitude = location.getQualifiedCoordinates().getLongitude();
_latitude = location.getQualifiedCoordinates().getLatitude();
_mapview.setZoom(Integer.parseInt("0.1"));
try
{
int latitude = (int) (100000 * _latitude);
int longitude = (int) (100000 * _longitude);
if (latitude > 9000000 || latitude < -9000000 || longitude >= 18000000 || longitude < -18000000)
{
throw new IllegalArgumentException ();
}
_mapview.setLatitude(latitude);
_mapview.setLongitude(longitude);
// Invoke BlackBerry Maps application with provided MapView object.
Invoke.invokeApplication(Invoke.APP_TYPE_MAPS, new MapsArguments(_mapview));
}
catch(RuntimeException re)
{
// An exception is thrown when any of the following occur :
// Latitude is invalid : Valid range: [-90, 90]
// Longitude is invalid : Valid range: [-180, 180)
// Minus sign between 2 numbers.
Dialog.alert("Temporary Unavailable Service");
}
}
}
/**
* #see javax.microedition.location.LocationListener#providerStateChanged(LocationProvider, int)
*/
public void providerStateChanged(LocationProvider provider, int newState)
{
if(newState == LocationProvider.TEMPORARILY_UNAVAILABLE)
{
provider.reset();
}
_screen.setState(newState);
}
}
/**
* The main screen to display the current GPS information
*/
private final class GPSDemoScreen extends MainScreen
{
TextField _statusTextField;
/**
* Create a new GPSDemoScreen object
*/
GPSDemoScreen()
{
// Initialize UI
_statusTextField = new TextField(Field.NON_FOCUSABLE);
}
/**
* Display the state of the GPS service
*
* #param newState The state to display
*/
public void setState(final int newState)
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
/**
* #see java.lang.Runnable#run()
*/
public void run()
{
switch(newState)
{
case LocationProvider.AVAILABLE:
_statusTextField.setText("Available");
break;
case LocationProvider.OUT_OF_SERVICE:
_statusTextField.setText("Out of Service");
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
_statusTextField.setText("Temporarily Unavailable");
break;
}
}
});
}
/**
* #see net.rim.device.api.ui.Screen#close()
*/
public void close()
{
if(_locationProvider != null)
{
_locationProvider.reset();
_locationProvider.setLocationListener(null, -1, -1, -1);
}
super.close();
}
}
}
I've seen that error when Dialog.alert() is used outside of the event thread. Looking at your code, I see LocationListenerImpl.locationUpdated assumes it is running on the event thread. If it is not, the UI update code would throw an exception, and then your exception handler will try to display a dialog, and that will fail as well.

Problem Running SSIS Package from Windows Service

I created a Windows Service that executes a SSIS Package every five minutes. It works pretty well, but something is tripping it up.
Every week the server restarts, and after the restart, the Service stops working. Events for the SSIS Package beginning/ending executions still appear in the event viewer, but the package doesn't work as it should. When I manually start/stop the service, all works as normal again.
Am I missing something that I should be doing with the Pacakge?
I use a web service to get the location of the SSIS Package. I stripped most of that out of the code below, but left enough of it that the structure of my service is maintained.
Here is the jist of my code:
namespace MyService
{
partial class MyService : ServiceBase
{
private Timer timer;
private Package pkg;
bool executing;
public MyService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
executing = false;
TimerCallback callback = new TimerCallback(Init);
int period = 1000 * 60; //attempt to initialize every minute.
timer = new Timer(callback, null, 0, period);
}
private void Init(object state)
{
try
{
//Get `timeIntervalMinutes` from Parameters table
string mySQLStatement = "...";
DataSet ds = mySQLQuery(...);
int timeIntervalMinutes = Convert.ToInt32(ds.Tables["timeIntervalMinutes"].Rows[0]["Value"]);
//Get `path` from Parameters table
string mySQLStatement = "...";
DataSet ds = mySQLQuery(...);
string path = Convert.ToString(ds.Tables["path"].Rows[0]["Value"]);
//Get `path` from Parameters table
string mySQLStatement = "...";
DataSet ds = mySQLQuery(...);
string server = Convert.ToString(ds.Tables["server"].Rows[0]["Value"]);
//Load the SSIS Package
Application app = new Application();
pkg = app.LoadFromDtsServer(path, server, null);
//If this line is reached, a connection to MyWS has been made, so switch the timer to run the SSIS package
timer.Dispose();
TimerCallback callback = new TimerCallback(OnTimedEvent);
int period = 1000 * 60 * timeIntervalMinutes;
timer = new Timer(callback, null, 0, period);
}
catch (Exception e)
{
return;
}
}
private void OnTimedEvent(object state)
{
if (!executing)
{
executing = true;
DTSExecResult pkgResults = pkg.Execute();
executing = false;
}
}
protected override void OnStop()
{
}
//<MyWS is here>
}
}
Thanks for the help!
Your service or process maybe dependent on another service - say MSDTC. IF this service is not ready as quickly after startup you could get unpredictable results. Either delay the startup of your service or figure out the dependency and set is in the service properties

Resources