I am using xamarin for crossplatform app development . We have used asure mobile service to connect with database . Basically This application is for chatting purpose so we have used SignalR with .NET Framework.When app comes from sleep after some duration like 60 seconds it get crashed. Is there any way to connect back using SignalR.Issue seems with SignalR. Where exactly do I need to update code at client side or server side .
Client side code
public class SignalRClient
{
private static string CONNECTION_URL = "http://";
private static TimeSpan CONNECT_TIMEOUT = new TimeSpan(0, 0, 30);
private readonly HubConnection _hubConnection;
private readonly IHubProxy _chatHubProxy;
private static string AuthToken = "";
public string UserID;
public event SignalRConnectionStateChangedDelegate SignalRConnectionStateChangedEvent;
public SignalRClient(string authToken)
{
AuthToken = authToken;
_hubConnection = new HubConnection(CONNECTION_URL);
_hubConnection.Headers["xauth"] = AuthToken;
_hubConnection.TransportConnectTimeout = CONNECT_TIMEOUT;
_hubConnection.Error += ex =>
{
if (SignalRConnectionStateChangedEvent != null)
{
_hubConnection.Stop();
SignalRConnectionStateChangedEvent("Error :" + ex.Message);
}
};
_chatHubProxy = _hubConnection.CreateHubProxy("ChatServer");
}
public async Task Connect(string UserID)
{
if (_hubConnection.State != ConnectionState.Connected)
{
try
{
await _hubConnection.Start();
_hubConnection.StateChanged += (connectionState) =>
{
if (SignalRConnectionStateChangedEvent != null)
{
SignalRConnectionStateChangedEvent(connectionState.NewState.ToString().ToLower());
}
};
}
catch (Exception ex)
{
var message = ex.Message;
}
Related
I have a Xamarin forms application. The application programmatically connects to a an access to point to communicate via sockets with a host machine connected to that same access point. The access point is not required to have internet access. When testing my code in iOS - I get a socket error stating that the 'Destination is unreachable'. However, if I go to settings and click on the wifi connection I want to use - I am taken to the login page for the access point. If I click cancel I get the option to 'Use without Internet'. If I select that option, then go back to my application, I am able to connect to the host. Is there a way to programmatically tell iOS to use the connecting even though it does not have internet? I looked at the Zone property but that is read only. Here is the code I am using. Any assistance would be appreciated.
public async Task<WifiConfiguredEventArgs> ConnectToWifi()
{
try
{
var tobj_WifiManager = new NEHotspotConfigurationManager();
var tobj_SSIDs = await tobj_WifiManager.GetConfiguredSsidsAsync();
if (tobj_SSIDs != null && tobj_SSIDs.Contains(App.gvm_AppSettings.WifiSSID))
{
// We are already connected -- just return
lobj_WifiConfiguredEventArgs.ConnectionStatus = FlexConnectionStatus.eAlreadyConnected;
}
else
{
var tobj_WifiConfig = new NEHotspotConfiguration(App.gvm_AppSettings.WifiSSID, App.gvm_AppSettings.WifiPassword, false);
tobj_WifiManager.ApplyConfiguration(tobj_WifiConfig, async (error) =>
{
if (error != null)
{
lobj_WifiConfiguredEventArgs.ConnectionStatus = FlexConnectionStatus.eErrorEstablishingConnection;
lobj_WifiConfiguredEventArgs.ErrorMessage = error.ToString();
}
else
{
lobj_WifiConfiguredEventArgs.ConnectionStatus = FlexConnectionStatus.eConnectionEstablished;
}
});
}
}
catch(Exception ex)
{
lobj_WifiConfiguredEventArgs.ConnectionStatus = FlexConnectionStatus.eErrorEstablishingConnection;
lobj_WifiConfiguredEventArgs.ErrorMessage = ex.Message;
lobj_WifiConfiguredEventArgs.ErrorException = ex;
App.ProcessException(ex);
}
return lobj_WifiConfiguredEventArgs;
}
}
Someone asked for the socket code so here it is. To be clear, the socket code connects and communicates fine in iOS when the access point has an internet connection. It also works fine in all the android calls.
using FCISelfCheckIn;
using FCISelfCheckIn.Resources;
using FCISharedAll.FCICommObjects;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using static FCISharedAll.FCIEnums.FlexEnums;
namespace FCISelfCheckIn
{
// This template use base socket syntax to change Pattern. (like Send, Receive, and so on)
// Convert to Task-based Asynchronous Pattern. (TAP)
public static class AsynchronousClientSocket
{
private static bool ib_IsConnected = false;
private static Socket iobj_Client = null;
public static async Task<MasterDataObject> SendMessage(string ps_IPAddress, int pi_Port, ge_CommunicationType pe_CommicationType,
string JSONData)
{
MasterDataObject lobj_response = new MasterDataObject();
try
{
//We should already be connected by the time we get here so just continue
//However if we are not - try to connect again
if (!ib_IsConnected)
{
// Establish the remote endpoint for the socket.
IPAddress ipAddress = IPAddress.Parse(ps_IPAddress);
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, pi_Port);
// Create a TCP/IP socket.
iobj_Client = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
ib_IsConnected = await iobj_Client.ConnectAsync(remoteEndPoint).ConfigureAwait(false);
}
if (ib_IsConnected)
{
var bytesSent = await iobj_Client.SendAsync(JSONData).ConfigureAwait(false);
// Receive the response from the remote device.
var ls_MasterDataObject = await iobj_Client.ReceiveAsync(60).ConfigureAwait(false);
if (ls_MasterDataObject == null)
{
lobj_response = new MasterDataObject();
lobj_response.CommunicationType = ge_CommunicationType.e_Error;
}
else
{
//deserialize the master data object in order to return it to the client
lobj_response = App.gvm_CommunicationHelper.DeserializeMasterDataObject(ls_MasterDataObject);
iobj_Client.Shutdown(SocketShutdown.Both);
}
}
else
{
lobj_response.CommunicationType = ge_CommunicationType.e_Error;
lobj_response.JSONDataObject = JsonConvert.SerializeObject(AppResources.ServerConnectionError);
}
// Release the socket.
iobj_Client.Close();
}
catch (Exception ex)
{
App.ProcessException(ex);
}
return lobj_response;
}
private static Task<bool> ConnectAsync(this Socket client, IPEndPoint remoteEndPoint)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (remoteEndPoint == null) throw new ArgumentNullException(nameof(remoteEndPoint));
return Task.Run(() => Connect(client, remoteEndPoint));
}
private static bool Connect(this Socket client, EndPoint remoteEndPoint)
{
bool lb_ReturnValue = true;
try
{
if (client == null || remoteEndPoint == null)
{
lb_ReturnValue = false;
}
else
{
client.Connect(remoteEndPoint);
}
}
catch (System.Net.Sockets.SocketException Socketex)
{
lb_ReturnValue = false;
if (Socketex.ErrorCode != 10061 && Socketex.ErrorCode != 10065)
{
//Dont log if the host is not running.
App.ProcessException(Socketex);
}
}
catch (Exception ex)
{
App.ProcessException(ex);
lb_ReturnValue = false;
}
return lb_ReturnValue;
}
private static async Task<string> ReceiveAsync(this Socket client, int waitForFirstDelaySeconds = 10)
{
if (client == null) throw new ArgumentNullException(nameof(client));
Debug.WriteLine("Receive Message 1");
// Timeout for wait to receive and prepare data.
for (var i = 0; i < waitForFirstDelaySeconds; i++)
{
if (client.Available > 0)
break;
await Task.Delay(3000).ConfigureAwait(false);
}
// return null If data is not available.
if (client.Available < 1)
return null;
Debug.WriteLine("Receive Message 2");
// Size of receive buffer.
const int bufferSize = 1024;
var buffer = new byte[bufferSize];
// Get data
var response = new StringBuilder(bufferSize);
do
{
var size = Math.Min(bufferSize, client.Available);
await Task.Run(() => client.Receive(buffer)).ConfigureAwait(false);
var ts_CurrentSegment = Encoding.ASCII.GetString(buffer, 0, size);
if (ts_CurrentSegment.Length > 0)
{
response.Append(Encoding.ASCII.GetString(buffer, 0, size));
}
} while (!response.ToString().EndsWith(FCIEndOfFile));
// Return result.
return response.ToString().Replace(FCIEndOfFile, "");
}
private static async Task<int> SendAsync(this Socket client, string data)
{
var byteData = Encoding.ASCII.GetBytes(data);
return await SendAsync(client, byteData, 0, byteData.Length, 0).ConfigureAwait(false);
}
private static Task<int> SendAsync(this Socket client, byte[] buffer, int offset,
int size, SocketFlags socketFlags)
{
if (client == null) throw new ArgumentNullException(nameof(client));
return Task.Run(() => client.Send(buffer, offset, size, socketFlags));
}
public async static Task<bool> ForcePermissions(string ps_IPAddress, int pi_Port)
{
bool lb_ReturnValue = false;
try
{
IPAddress ipAddress = IPAddress.Parse(ps_IPAddress);
//This is only done to force the local network permissions access in iOS 14.
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, pi_Port);
// Create a TCP/IP socket.
iobj_Client = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
ib_IsConnected = await iobj_Client.ConnectAsync(remoteEndPoint).ConfigureAwait(false);
if (ib_IsConnected)
{
Debug.WriteLine("GEORGE Permissions Connected");
//client.Shutdown(SocketShutdown.Both);
//client.Close();
lb_ReturnValue = true;
}
else
{
Debug.WriteLine("George Permissions not Connected");
}
}
catch (Exception ex)
{
//Just skip if there is an exception
App.ProcessException(ex);
}
return lb_ReturnValue;
}
}
}
I have a .Net core console application, that uses Confluent.Kafka.
I build a consumer for consuming messages from specific topic.
the app is intended to run a few times every-day, consume the messages on the specified topic and process them.
It took me a while to understand the consumer's vehavior, but the it will consume messages only if its groupId is a one that was never in use before.
Every time I change the consumer's groupId - the comsumer will fetch the messages in the subscribed topic. But on the next runs - with same groupId - the consumer.Consume returns null.
This behvior seems rlated to rebalance between consumers on same group. But I don't understand why - since the consumer should exist only throughout the application liftime. Before leaving the app, I call to consumer.close() and consumer.Dispose(). These should destoy the consumer, so that on the next run, when I create the consumer, again it will be the first and single consumer on the specified groupId. But as I said, this is not what happens in fact.
I know there are messages on the topic - I check it via command-line. And I also made sure the topic has only 1 partition.
The most weird thing is, that I have another .net core console app, which does the same process - and with no issue at all.
I attach the codes of the 2 apps.
Working app - always consuming:
class Program
{
...
static void Main(string[] args)
{
if (args.Length != 2)
{
Console.WriteLine("Please provide topic name to read and SMTP topic name");
}
else
{
var services = new ServiceCollection();
services.AddSingleton<ConsumerConfig, ConsumerConfig>();
services.AddSingleton<ProducerConfig, ProducerConfig>();
var serviceProvider = services.BuildServiceProvider();
var cConfig = serviceProvider.GetService<ConsumerConfig>();
var pConfig = serviceProvider.GetService<ProducerConfig>();
cConfig.BootstrapServers = Environment.GetEnvironmentVariable("consumer_bootstrap_servers");
cConfig.GroupId = "confluence-consumer";
cConfig.EnableAutoCommit = true;
cConfig.StatisticsIntervalMs = 5000;
cConfig.SessionTimeoutMs = 6000;
cConfig.AutoOffsetReset = AutoOffsetReset.Earliest;
cConfig.EnablePartitionEof = true;
pConfig.BootstrapServers = Environment.GetEnvironmentVariable("producer_bootstrap_servers");
var consumer = new ConsumerHelper(cConfig, args[0]);
messages = new Dictionary<string, Dictionary<string, UserMsg>>();
var result = consumer.ReadMessage();
while (result != null && !result.IsPartitionEOF)
{
Console.WriteLine($"Current consumed msg-json: {result.Message.Value}");
...
result = consumer.ReadMessage();
}
consumer.Close();
Console.WriteLine($"Done consuming messages from topic {args[0]}");
}
}
class ConsumerHelper.cs
namespace AggregateMailing
{
using System;
using Confluent.Kafka;
public class ConsumerHelper
{
private string _topicName;
private ConsumerConfig _consumerConfig;
private IConsumer<string, string> _consumer;
public ConsumerHelper(ConsumerConfig consumerConfig, string topicName)
{
try
{
_topicName = topicName;
_consumerConfig = consumerConfig;
var builder = new ConsumerBuilder<string, string>(_consumerConfig);
_consumer = builder.Build();
_consumer.Subscribe(_topicName);
}
catch (System.Exception exc)
{
Console.WriteLine($"Error on ConsumerHelper: {exc.ToString()}");
}
}
public ConsumeResult<string, string> ReadMessage()
{
Console.WriteLine("ReadMessage: start");
try
{
return _consumer.Consume();
}
catch (System.Exception exc)
{
Console.WriteLine($"Error on ReadMessage: {exc.ToString()}");
return null;
}
}
public void Close()
{
Console.WriteLine("Close: start");
try
{
_consumer.Close();
_consumer.Dispose();
}
catch (System.Exception exc)
{
Console.WriteLine($"Error on Close: {exc.ToString()}");
}
}
}
}
Not working app - consuming only on first run after changing consumer groupId to one never in use:
class Program.cs
class Program
{
private static SmtpClient smtpClient;
private static Random random = new Random();
static void Main(string[] args)
{
try
{
var services = new ServiceCollection();
services.AddSingleton<ConsumerConfig, ConsumerConfig>();
services.AddSingleton<SmtpClient>(new SmtpClient("smtp.gmail.com"));
var serviceProvider = services.BuildServiceProvider();
var cConfig = serviceProvider.GetService<ConsumerConfig>();
cConfig.BootstrapServers = Environment.GetEnvironmentVariable("consumer_bootstrap_servers");
cConfig.GroupId = "smtp-consumer";
cConfig.EnableAutoCommit = true;
cConfig.StatisticsIntervalMs = 5000;
cConfig.SessionTimeoutMs = 6000;
cConfig.AutoOffsetReset = AutoOffsetReset.Earliest;
cConfig.EnablePartitionEof = true;
var consumer = new ConsumerHelper(cConfig, args[0]);
...
var result = consumer.ReadMessage();
while (result != null && !result.IsPartitionEOF)
{
Console.WriteLine($"current consumed message: {result.Message.Value}");
var msg = JsonConvert.DeserializeObject<EmailMsg>(result.Message.Value);
result = consumer.ReadMessage();
}
Console.WriteLine("Done sending emails consumed from SMTP topic");
consumer.Close();
}
catch (System.Exception exc)
{
Console.WriteLine($"Error on Main: {exc.ToString()}");
}
}
class ConsumerHelper.cs
using Confluent.Kafka;
using System;
using System.Collections.Generic;
namespace Mailer
{
public class ConsumerHelper
{
private string _topicName;
private ConsumerConfig _consumerConfig;
private IConsumer<string, string> _consumer;
public ConsumerHelper(ConsumerConfig consumerConfig, string topicName)
{
try
{
_topicName = topicName;
_consumerConfig = consumerConfig;
var builder = new ConsumerBuilder<string, string> (_consumerConfig);
_consumer = builder.Build();
_consumer.Subscribe(_topicName);
//_consumer.Assign(new TopicPartition(_topicName, 0));
}
catch (System.Exception exc)
{
Console.WriteLine($"Error on ConsumerHelper: {exc.ToString()}");
}
}
public ConsumeResult<string, string> ReadMessage()
{
Console.WriteLine("ConsumeResult: start");
try
{
return _consumer.Consume();
}
catch (System.Exception exc)
{
Console.WriteLine($"Error on ConsumeResult: {exc.ToString()}");
return null;
}
}
public void Close()
{
Console.WriteLine("Close: start");
try
{
_consumer.Close();
_consumer.Dispose();
}
catch (System.Exception exc)
{
Console.WriteLine($"Error on Close: {exc.ToString()}");
}
Console.WriteLine("Close: end");
}
}
}
I'm new to Xamarin.Forms and I'm making a Listview that needs to update every time I insert new information in the database, so far I can display the info of my list and add it via a PHP file but I can't make it refresh automatically.
namespace Proyect
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Alarms : ContentPage
{
public Alarms ()
{
InitializeComponent();
AlarmsList.ItemTemplate = new DataTemplate(typeof(Cells.AlarmsCell)); //Template of the Alarms
this.LoadAlarms();
}
private async void LoadAlarms()
{
try
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("Http://192.168.0.13");
string url = string.Format("/Proyect/alarmscode.php?");
var response = await client.GetAsync(url);
var result = response.Content.ReadAsStringAsync().Result;
var jsonalarms = JsonConvert.DeserializeObject<ObservableCollection<GetAlarms>>(result);
AlarmsList.ItemsSource = jsonalarms;
}
catch (Exception e)
{
await DisplayAlert("ERROR", e + "", "OK");
return;
}
}
}
}
Can you try to keep the same ObservableCollection and update its content instead of setting a new ObservableCollection every time?
namespace Proyect
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Alarms : ContentPage
{
private ObservableCollection<GetAlarms> _itemsSource = null;
public Alarms()
{
InitializeComponent();
AlarmsList.ItemTemplate = new DataTemplate(typeof(Cells.AlarmsCell)); //Template of the Alarms
_itemsSource = new ObservableCollection<GetAlarms>();
AlarmsList.ItemsSource = _itemsSource;
this.LoadAlarms();
}
private async void LoadAlarms()
{
try
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("Http://192.168.0.13");
string url = string.Format("/Proyect/alarmscode.php?");
var response = await client.GetAsync(url);
var result = response.Content.ReadAsStringAsync().Result;
var jsonalarms = JsonConvert.DeserializeObject<ObservableCollection<GetAlarms>>(result);
_itemsSource.Clear();
foreach (var alarm in jsonalarms)
{
_itemsSource.Add(alarm);
}
}
catch (Exception e)
{
await DisplayAlert("ERROR", e + "", "OK");
return;
}
}
}
}
Device.StartTimer (new TimeSpan (0, 0, 10), () => {
// do something every 10 seconds
return true; // runs again, or false to stop
});
I am trying to implement Stripe.net into my Xamarin.Forms PCL using an ASP.NET Core MVC Web API. The goal is to process credit card payment from users. My web API runs locally on http://localhost:port for testing purposes.
In the PaymentPage, a user enters their credit card information into Entry objects and when they click the submit Button, a method in the PaymentPageViewModel is called to start the logic:
async void OnFinishBookingClicked(object sender, System.EventArgs e)
{
// TODO: Stripe integration
var viewModel = (PaymentPageViewModel)this.BindingContext;
await viewModel.ProcessPayment();
}
This is part of the PaymentPageViewModel:
private readonly IStripeRepository _repository;
private readonly IAPIRepository _api;
public PaymentPageViewModel(IStripeRepository repository, IAPIRepository api)
{
_repository = repository;
_api = api;
}
public async Task ProcessPayment()
{
try
{
if (string.IsNullOrEmpty(ExpirationDate))
ExpirationDate = "09/18";
var exp = ExpirationDate.Split('/');
var token = _repository.CreateToken(CreditCardNumber, exp[0], exp[1], SecurityCode);
await Application.Current.MainPage.DisplayAlert("Test Message", token, "OK");
await _api.ChargeCard(token, 5.00M);
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "OK");
}
}
This is what the APIRepository looks like:
public class APIRepository: IAPIRepository
{
const string Url = "http://localhost:5000";
private string authorizationKey;
private async Task<HttpClient> GetClient()
{
HttpClient client = new HttpClient();
if (string.IsNullOrEmpty(authorizationKey))
{
authorizationKey = await client.GetStringAsync(Url);
authorizationKey = JsonConvert.DeserializeObject<string>(authorizationKey);
}
client.DefaultRequestHeaders.Add("Authorization", authorizationKey);
client.DefaultRequestHeaders.Add("Accept", "application/json");
return client;
}
public async Task<string> ChargeCard(string token, decimal amount)
{
HttpClient client = await GetClient();
var json = JsonConvert.SerializeObject(new { token, amount });
var response = await client.PostAsync("/api/Stripe", new StringContent(json));
return await response.Content.ReadAsStringAsync();
}
}
The issue is that I get a series of errors during await _api.ChargeCard(token, 5.00M):
The first exception happens during authorizationKey = await client.GetStringAsync(Url); the exception message is the following:
{System.Net.Http.HttpRequestException: 404 (Not Found) at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode () [0x0000a] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.2.0.11/src/mono/mcs/class/System.Net.Http/System.Net.Http/HttpResponseM…}
I get another exception during response = await client.PostAsync("/api/Stripe", new StringContent(json));
{System.InvalidOperationException: The request URI must either be an absolute URI or BaseAddress must be set at System.Net.Http.HttpClient.SendAsync (System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpCompletionOption completionOption, System.Thr…}
The third exception happens at the catch block of the viewModel.ProcessPayment() method:
{System.NullReferenceException: Object reference not set to an instance of an object at Zwaby.Services.APIRepository+d__3.MoveNext () [0x00184] in /Users/carlos/Projects/Zwaby/Zwaby/Services/APIRepository.cs:57 --- End of stack trace from previou…}
In my Web API project, I have a StripeController, but my implementation may not be fully correct:
[Route("api/Stripe")]
public class StripeController : Controller
{
private readonly StripeContext _context;
public StripeController(StripeContext context)
{
_context = context;
if (_context.StripeCharges.Count() == 0)
{
_context.StripeCharges.Add(new StripeItem { });
_context.SaveChanges();
}
}
[HttpGet]
public IActionResult Get(string key)
{
// TODO: implement method that returns authorization key
}
[HttpPost]
public IActionResult Charge(string stripeToken, decimal amount)
{
var customers = new StripeCustomerService();
var charges = new StripeChargeService();
var customer = customers.Create(new StripeCustomerCreateOptions
{
SourceToken = stripeToken
});
var charge = charges.Create(new StripeChargeCreateOptions
{
Amount = (int)amount,
Description = "Sample Charge",
Currency = "usd",
CustomerId = customer.Id
});
return View();
}
}
For completeness, I am including the StripeRepository class, the other parameter of the PaymentPageViewModel:
public class StripeRepository: IStripeRepository
{
public string CreateToken(string cardNumber, string cardExpMonth, string cardExpYear, string cardCVC)
{
StripeConfiguration.SetApiKey("my_test_key");
//TODO: Wireup card information below
var tokenOptions = new StripeTokenCreateOptions()
{
Card = new StripeCreditCardOptions()
{
Number = "4242424242424242",
ExpirationYear = 2018,
ExpirationMonth = 10,
Cvc = "123"
}
};
var tokenService = new StripeTokenService();
StripeToken stripeToken = tokenService.Create(tokenOptions);
return stripeToken.Id;
}
}
Thank you so much!
I have java SE sample client which run on desktop (code below). But I have access to WebSphere were called EJB is deployed. How to rewrite below code to work on WebSphere? (When I leave this code just like it is program works but I think this can be done more simple and clear)
Main method:
WSConn connection = new WSConn();
final Plan plan = connection.getPlanBean();
com.ibm.websphere.security.auth.WSSubject.doAs(connection.getSubject(), new java.security.PrivilegedAction<Object>() {
public Object run() {
try {
// App logic
} catch (Throwable t) {
System.err.println("PrivilegedAction - Error calling EJB: " + t);
t.printStackTrace();
}
return null;
}
}); // end doAs
WSConn class:
public class WSConn {
private static final String INITIAL_CONTEXT_FACTORY = "com.ibm.websphere.naming.WsnInitialContextFactory";
private static final String JAAS_MODULE = "WSLogin";
private static final String MODEL_EJB_NAME_LONG = "ejb/com/ibm/ModelHome";
private static final String PLAN_EJB_NAME_LONG = "ejb/com/ibm/PlanHome";
private Subject subject;
private InitialContext initialContext;
private String serverName;
private String serverPort;
private String uid;
private String pwd;
private String remoteServerName;
private Model modelBean;
private Plan planBean;
public WSConn() {
Properties props = new Properties();
try {
props.load(WSConn.class.getClassLoader().getResourceAsStream("WSConn.properties"));
} catch (IOException e) {
e.printStackTrace();
}
serverName = props.getProperty("WSConn.serverName");
serverPort = props.getProperty("WSConn.serverPort");
uid = props.getProperty("WSConn.userID");
pwd = props.getProperty("WSConn.password");
remoteServerName = props.getProperty("WSConn.remoteServerName");
}
private void init() {
if (subject == null || initialContext == null) {
subject = login();
}
}
private Subject login() {
Subject subject = null;
try {
LoginContext lc = null;
// CRATE LOGIN CONTEXT
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
env.put(Context.PROVIDER_URL, "corbaloc:iiop:" + serverName + ":" + serverPort);
initialContext = new InitialContext(env);
// Just to test the connection
initialContext.lookup("");
lc = new LoginContext(JAAS_MODULE, new WSCallbackHandlerImpl(uid, pwd));
lc.login();
subject = lc.getSubject();
} catch (javax.naming.NoPermissionException exc) {
System.err.println("[WSConn] - Login Error: " + exc);
} catch (Exception exc) {
System.err.println("[WSConn] - Error: " + exc);
}
return subject;
}
public wModel getModelBean() {
if (modelBean == null) {
init();
modelBean = (wModel) com.ibm.websphere.security.auth.WSSubject.doAs(subject,
new java.security.PrivilegedAction<wModel>() {
public wModel run() {
wModel session = null;
try {
Object o = initialContext.lookup(MODEL_EJB_NAME_LONG);
wModelHome home = (wModelHome) PortableRemoteObject.narrow(o, wModelHome.class);
if (home != null) {
session = home.create(remoteServerName);
}
} catch (Exception exc) {
System.err.println("Error getting model bean: " + exc);
}
return session;
}
}); // end doAs
}
return modelBean;
}
public wPlan getPlanBean() {
if (planBean == null) {
init();
planBean = (wPlan) com.ibm.websphere.security.auth.WSSubject.doAs(subject,
new java.security.PrivilegedAction<wPlan>() {
public wPlan run() {
wPlan session = null;
try {
Object o = initialContext.lookup(PLAN_EJB_NAME_LONG);
wPlanHome home = (wPlanHome) PortableRemoteObject.narrow(o, wPlanHome.class);
if (home != null) {
session = home.create(remoteServerName);
}
} catch (Exception exc) {
System.err.println("Error getting plan bean: " + exc);
}
return session;
}
}); // end doAs
}
return planBean;
}
public Subject getSubject() {
if (subject == null) {
init();
}
return subject;
}
}
As indicated in another answer, the classic mechanism is to lookup and narrow the home interface.
Get the initial context
final InitialContext initialContext = new InitialContext();
Lookup for the home by jndi name, specifying either the full jndi name
Object obj = initialContext.lookup("ejb/com/ibm/tws/conn/plan/ConnPlanHome");
or you can create e reference in your WAR and use java:comp/env/yourname
Then narrow the home to the home interface class
ConnPlanHome planHome = (ConnPlanHome)PortableRemoteObject.narrow(obj, ConnPlanHome.class);
and then create the EJB remote interface
ConnPlan plan = planHome.create();
The about calls should work for IBM Workload Scheduler distributed.
For IBM Workload Scheduler z/OS the JNDI name and the class names are different:
final InitialContext initialContext = new InitialContext();
String engineName = "XXXX";
Object obj = initialContext.lookup("ejb/com/ibm/tws/zconn/plan/ZConnPlanHome");
ZConnPlanHome planHome = (ZConnPlanHome)PortableRemoteObject.narrow(obj, ZConnPlanHome.class);
ZConnPlan plan = planHome.create(engineName);
User credentials are propagated from the client to the engine, the client need to be authenticated otherwise the engine will reject the request.
If you're trying to access an EJB from a POJO class, then there is nothing more simple than lookup+narrow. However, if the POJO is included in an application (EAR or WAR), then you could declare and lookup an EJB reference (java:comp/ejb/myEJB), and then the container would perform the narrow rather than your code. If you change your code to be a managed class like a servlet, another EJB, or a CDI bean, then you could use #EJB injection, and then you would not even need a lookup.