I have a SharePoint project with Event Receivers in it and the solution deploys fine as long as I leave out one specific Event Receiver off the list.
If I add that Event Receiver to the Feature list I get the following error:
‘Error occurred in deployment step ‘Activate Features’:
This project wasn't started by me and I am a bit of a novice when it comes to Event Receiver projects.
Add this logging method and log messages in the FeatureActivated method. Or you can debug the feature during activation with Visual Studio.
/// <summary>
/// Method used for logging errors to a log located at c:\log on the WFE
/// </summary>
/// <param name="msg"></param>
static void LogMessage(string msg)
{
StreamWriter wrtr = null;
try
{
wrtr = new StreamWriter("C:\\Logs\\eventreceiver.txt", true);
wrtr.WriteLine(msg + "--[" + System.DateTime.Now.ToString() + "]" + Environment.NewLine);
wrtr.WriteLine(Environment.NewLine + "==================================");
}
catch (Exception e)
{
throw e;
}
finally
{
if (wrtr != null)
{
wrtr.Close();
wrtr.Dispose();
}
}
}
Related
I'm a little bit confused on how to use IoT Edge Offline mode. I though it was out-of-box!
The location of my IoT Hub is in West US. When I disconnect my Edge device from the network nothing happen. The datas is not saved or resend after reconnecting it online.
I got only one module that send data to the IoT Hub, I can see the datas flowing with Device Explorer Twin app and I saved the data in a database.
After disconnecting, wait 5 minutes and reconnecting, I don't see the datas that I was trying to send during offline mode in the database.
All messages while offline are missing (I'm sequencing the message with datetime stamp).
Did I missed a configuration?
Any idea why the offline mode doesn't work for me?
I'm using Iot Edge Runtime v1.0.6 and Windows Containers.
Here the source code of my testing module:
using Microsoft.Azure.Devices.Client;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Runtime.Loader;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static int monitoringInterval { get; set; } = 60;// 60 seconds
static System.Timers.Timer testTimer;
static ModuleClient ioTHubModuleClient;
static void Main(string[] args)
{
Init().Wait();
StartTestTimer();
// Wait until the app unloads or is cancelled
var cts = new CancellationTokenSource();
AssemblyLoadContext.Default.Unloading += (ctx) => cts.Cancel();
Console.CancelKeyPress += (sender, cpe) => cts.Cancel();
WhenCancelled(cts.Token).Wait();
}
/// <summary>
/// Handles cleanup operations when app is cancelled or unloads
/// </summary>
public static Task WhenCancelled(CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).SetResult(true), tcs);
return tcs.Task;
}
/// <summary>
/// Initializes the ModuleClient and sets up the callback to receive
/// messages containing temperature information
/// </summary>
static async Task Init()
{
AmqpTransportSettings amqpSetting = new AmqpTransportSettings(TransportType.Amqp_Tcp_Only);
ITransportSettings[] settings = { amqpSetting };
// Open a connection to the Edge runtime
ioTHubModuleClient = await ModuleClient.CreateFromEnvironmentAsync(settings);
await ioTHubModuleClient.OpenAsync();
Console.WriteLine("IoT Hub module client initialized.");
}
static void StartTestTimer()
{
Console.WriteLine("Start Monitoring Timer: " + monitoringInterval + " seconds");
// Set up a timer that triggers every minute.
testTimer = new System.Timers.Timer();
testTimer.Interval = monitoringInterval * 1000; // 60 seconds
testTimer.Elapsed += new System.Timers.ElapsedEventHandler(SendEvent);
testTimer.Start();
SendEvent(null, null);
}
async static void SendEvent(object sender, System.Timers.ElapsedEventArgs args)
{
DateTime today = DateTime.Now;
Console.WriteLine("[" + today + "] Send Data has started...");
try
{
//IoT device connection string
string connectionString = "HostName=xxxxxx.azure-devices.net;DeviceId=IOT-Device1;SharedAccessKey=ett8xxxxxxxxx";
// Connect to the IoT hub using the MQTT protocol
DeviceClient _DeviceClient = DeviceClient.CreateFromConnectionString(connectionString, TransportType.Mqtt);
_DeviceClient.OperationTimeoutInMilliseconds = 10000;
Dictionary<string, Object> telemetryDataPoint = new Dictionary<string, Object>();
string dateTime = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString();
telemetryDataPoint.Add("DateTime", dateTime);
string messageString = JsonConvert.SerializeObject(telemetryDataPoint);
Message message = new Message(Encoding.ASCII.GetBytes(messageString));
// Send the telemetry message
Console.WriteLine("\n*> Sending message: {0}", messageString);
await _DeviceClient.SendEventAsync(message).ConfigureAwait(false);
Console.WriteLine("Message sent!");
}
catch (Exception e)
{
Console.WriteLine("Message not sent. Connection error to Iot Hub:" + e.Message);
}
}
}
Why is the code creating a moduleClient in Init(), but then attempting to send an a message directly to IoT Hub using a deviceClient in SendEvent()? This bypasses the edge runtime (specifically edgeHub) completely which is what facilitates offline store and forward.
Here is an example of the right way to do this: https://github.com/Azure/iotedge/blob/ad41fec507bb91a2e57a07cd32e287ada0ca08d8/edge-modules/SimulatedTemperatureSensor/src/Program.cs#L95
When invoking a direct method on a specific module I just receive the result [object Object] in the azure portal and I don't know what I'm doing wrong.
Note that when I did exactly the same using the azure IoT SDK for c# (without running the azure iot runtime), I properly received the JSON object and it was not just shown as [object Object].
Note that I'm developing this in c# and the docker containers (used for IoT edge runtime and it's modules) is running Linux as OS.
I have the following sample method that I've registered as a direct method.
In the iot edge runtime Init() function I do the following:
await ioTHubModuleClient.SetMethodHandlerAsync("Sample1", Sample1, null);
The sample method looks like:
private static Task<MethodResponse> Sample1(MethodRequest methodRequest, object userContext)
{
// Get data but don't do anything with it... Works fine!
var data = Encoding.UTF8.GetString(methodRequest.Data);
var methodResponse = new MethodResponse(Encoding.UTF8.GetBytes("{\"status\": \"ok\"}"), 200);
return Task.FromResult(methodResponse);
}
I can monitor this module in the debug mode by setting breakpoints in the Sample1 method. I can't find what I'm doing wrong? Why is the response returned from this Sample1 method just shown as [object Object] and why don't I see the JSON-object {"status": "ok"} as I did when not using the Azure IoT Edge runtime?
The callback result for the Direct Method is object Task< MethodResponse >.It does not serialize to Json string to show in the Azure Portal. But you can use the Service Client Sdk to get the callback response and then serialize to JSON string.
The latest Microsoft Azure IoT Hub SDK for C# supports Modules and IoT Edge. You can refer to this sample with using the SDK.
Update:
In the latest Azure IoT Hub SDK(Microsoft.Azure.Devices.Client 1.18), please use ModuleClinet instead of DeviceClient. You can refer to the following code in module.
namespace SampleModuleA
{
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Client.Transport.Mqtt;
using Microsoft.Azure.Devices.Client;
using Newtonsoft.Json;
class Program
{
static int counter;
static void Main(string[] args)
{
Init().Wait();
// Wait until the app unloads or is cancelled
var cts = new CancellationTokenSource();
AssemblyLoadContext.Default.Unloading += (ctx) => cts.Cancel();
Console.CancelKeyPress += (sender, cpe) => cts.Cancel();
WhenCancelled(cts.Token).Wait();
}
/// <summary>
/// Handles cleanup operations when app is cancelled or unloads
/// </summary>
public static Task WhenCancelled(CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).SetResult(true), tcs);
return tcs.Task;
}
/// <summary>
/// Initializes the ModuleClient and sets up the callback to receive
/// messages containing temperature information
/// </summary>
static async Task Init()
{
MqttTransportSettings mqttSetting = new MqttTransportSettings(TransportType.Mqtt_WebSocket_Only);
ITransportSettings[] settings = { mqttSetting };
// Open a connection to the Edge runtime
ModuleClient ioTHubModuleClient = await ModuleClient.CreateFromEnvironmentAsync(settings);
await ioTHubModuleClient.OpenAsync();
Console.WriteLine("[{0:HH:mm:ss ffff}]IoT Hub SampleModuleA client initialized.", DateTime.Now);
await ioTHubModuleClient.SetMethodHandlerAsync("DirectMethod1", DirectMethod1, ioTHubModuleClient);
// Register callback to be called when a message is received by the module
await ioTHubModuleClient.SetInputMessageHandlerAsync("input1", PipeMessage, ioTHubModuleClient);
}
static async Task<MethodResponse> DirectMethod1(MethodRequest methodRequest, object moduleClient)
{
Console.WriteLine("Call DirectMethod1.");
MethodResponse resp = null;
//to do Something
return resp;
}
/// <summary>
/// This method is called whenever the module is sent a message from the EdgeHub.
/// It just pipe the messages without any change.
/// It prints all the incoming messages.
/// </summary>
static async Task<MessageResponse> PipeMessage(Message message, object userContext)
{
int counterValue = Interlocked.Increment(ref counter);
var moduleClient = userContext as ModuleClient;
if (moduleClient == null)
{
throw new InvalidOperationException("UserContext doesn't contain " + "expected values");
}
byte[] messageBytes = message.GetBytes();
string messageString = Encoding.UTF8.GetString(messageBytes);
Console.WriteLine($"Received message: {counterValue}, Body: [{messageString}]");
if (!string.IsNullOrEmpty(messageString))
{
var pipeMessage = new Message(messageBytes);
foreach (var prop in message.Properties)
{
pipeMessage.Properties.Add(prop.Key, prop.Value);
}
await moduleClient.SendEventAsync("output1", pipeMessage);
Console.WriteLine("Received message sent");
}
return MessageResponse.Completed;
}
}
}
I am new to UCMA and I am learning as I go through examples. I am trying to build 2 Lync clients A and B with the scenario as follows,
A calls B
B answers
A plays audio
B records it using Recorder.
I am stuck at trying to record the call at B. For B its an incoming call. I need to attach the audiovideoflow to the recorder, but I am not sure on how to do it. I will appreciate any help.
Apologies on the unformatted code, I am not sure how to format it properly, I tried.
Thanks.
Kris
Client B Code:
Accepts an incoming call
Records the media received in the incoming call. ***This is the part I have trouble
using System;
using System.Threading;
using Microsoft.Rtc.Collaboration;
using Microsoft.Rtc.Collaboration.AudioVideo;
using Microsoft.Rtc.Signaling;
using Microsoft.Rtc.Collaboration.Lync;
namespace Microsoft.Rtc.Collaboration.LyncUAS
{
public class LyncUAS
{
#region Locals
private LyncUASConfigurationHelper _helper;
private UserEndpoint _userEndpoint;
private AudioVideoCall _audioVideoCall;
private AudioVideoFlow _audioVideoFlow;
private Conversation _incomingConversation;
//Wait handles are only present to keep things synchronous and easy to read.
private AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
private EventHandler<AudioVideoFlowConfigurationRequestedEventArgs> _audioVideoFlowConfigurationRequestedEventHandler;
private EventHandler<MediaFlowStateChangedEventArgs> _audioVideoFlowStateChangedEventHandler;
private AutoResetEvent _waitForAudioVideoCallEstablishCompleted = new AutoResetEvent(false);
private AutoResetEvent _waitForAudioVideoFlowStateChangedToActiveCompleted = new AutoResetEvent(false);
private AutoResetEvent _waitForPrepareSourceCompleted = new AutoResetEvent(false);
#endregion
#region Methods
/// <summary>
/// Instantiate and run the DeclineIncomingCall quickstart.
/// </summary>
/// <param name="args">unused</param>
public static void Main(string[] args)
{
LyncUAS lyncUAS = new LyncUAS();
lyncUAS.Run();
}
private void Run()
{
string filename = "received.wma";
_helper = new LyncUASConfigurationHelper();
// Create a user endpoint, using the network credential object
// defined above.
_userEndpoint = _helper.CreateEstablishedUserEndpoint("Lync UAS" /*endpointFriendlyName*/);
_userEndpoint.RegisterForIncomingCall<AudioVideoCall>(On_AudioVideoCall_Received);
Console.WriteLine("Waiting for incoming call...");
_autoResetEvent.WaitOne();
Console.WriteLine("came after call is connected");
//start recording for audio.
Recorder recorder = new Recorder();
recorder.StateChanged += new EventHandler<RecorderStateChangedEventArgs>(recorder_StateChanged);
recorder.VoiceActivityChanged += new EventHandler<VoiceActivityChangedEventArgs>(recorder_VoiceActivityChanged);
//**********This is the issue, currently _audioVideoFlow is null, it is not attached to the flow
//So this will fail, how to attach _audioVideoFlow to an incoming call ?? HELP !!!
// recorder.AttachFlow(_audioVideoFlow); ------------> HELP!
WmaFileSink sink = new WmaFileSink(filename);
recorder.SetSink(sink);
recorder.Start();
Console.WriteLine("Started Recording ...");
_autoResetEvent.WaitOne();
recorder.Stop();
Console.WriteLine("Stopped Recording ...");
recorder.DetachFlow();
Console.WriteLine("Exiting");
Thread.Sleep(2000);
}
private void audioVideoFlow_StateChanged(object sender, MediaFlowStateChangedEventArgs e)
{
Console.WriteLine("Flow state changed from " + e.PreviousState + " to " + e.State);
//When flow is active, media operations can begin
if (e.State == MediaFlowState.Active)
{
// Flow-related media operations normally begin here.
_waitForAudioVideoFlowStateChangedToActiveCompleted.Set();
}
// call sample event handler
if (_audioVideoFlowStateChangedEventHandler != null)
{
_audioVideoFlowStateChangedEventHandler(sender, e);
}
}
void recorder_VoiceActivityChanged(object sender, VoiceActivityChangedEventArgs e)
{
Console.WriteLine("Recorder detected " + (e.IsVoice ? "voice" : "silence") + " at " + e.TimeStamp);
}
void recorder_StateChanged(object sender, RecorderStateChangedEventArgs e)
{
Console.WriteLine("Recorder state changed from " + e.PreviousState + " to " + e.State);
}
void On_AudioVideoCall_Received(object sender, CallReceivedEventArgs<AudioVideoCall> e)
{
//Type checking was done by the platform; no risk of this being any
// type other than the type expected.
_audioVideoCall = e.Call;
// Call: StateChanged: Only hooked up for logging, to show the call
// state transitions.
_audioVideoCall.StateChanged += new
EventHandler<CallStateChangedEventArgs>(_audioVideoCall_StateChanged);
_incomingConversation = new Conversation(_userEndpoint);
Console.WriteLine("Call Received! From: " + e.RemoteParticipant.Uri + " Toast is: " +e.ToastMessage.Message);
_audioVideoCall.BeginAccept(
ar =>
{
try {
_audioVideoCall.EndAccept(ar);
Console.WriteLine("Call must be connected at this point. "+_audioVideoCall.State);
_autoResetEvent.Set();
} catch (RealTimeException ex) { Console.WriteLine(ex); }
}, null);
}
//Just to record the state transitions in the console.
void _audioVideoCall_StateChanged(object sender, CallStateChangedEventArgs e)
{
Console.WriteLine("Call has changed state. The previous call state was: " + e.PreviousState +
" and the current state is: " + e.State);
if (e.State == CallState.Terminated)
{
Console.WriteLine("Shutting down");
_autoResetEvent.Set();
_helper.ShutdownPlatform();
}
}
#endregion
}
}
I think I have figured out what's not quite right here.
Your Code
// Create a user endpoint, using the network credential object
// defined above.
_userEndpoint = _helper.CreateEstablishedUserEndpoint("Lync UAS" /*endpointFriendlyName*/);
_userEndpoint.RegisterForIncomingCall<AudioVideoCall>(On_AudioVideoCall_Received);
Console.WriteLine("Waiting for incoming call...");
_autoResetEvent.WaitOne();
Console.WriteLine("came after call is connected");
//start recording for audio.
Recorder recorder = new Recorder();
recorder.StateChanged += new EventHandler<RecorderStateChangedEventArgs>(recorder_StateChanged);
recorder.VoiceActivityChanged += new EventHandler<VoiceActivityChangedEventArgs>(recorder_VoiceActivityChanged);
//**********This is the issue, currently _audioVideoFlow is null, it is not attached to the flow //So this will fail, how to attach _audioVideoFlow to an incoming call ?? HELP !!!
// recorder.AttachFlow(_audioVideoFlow); ------------> HELP!
Looking good so far. I'm assuming you're establishing and such in your CreateEstablishedUserEndpoint method, but I'm not seeing where you're getting the value for _audioVideoFlow.
I'm guessing you might be doing it elsewhere, but on the off chance that's actually where you're running into problems, here's that bit:
Simplest pattern to get AVFlow
public static void RegisterForIncomingCall(LocalEndpoint localEndpoint)
{
localEndpoint.RegisterForIncomingCall
<AudioVideoCall>(IncomingCallDelegate);
}
private static void IncomingCallDelegate(object sender, CallReceivedEventArgs<AudioVideoCall> e)
{
e.Call.AudioVideoFlowConfigurationRequested += IncomingCallOnAudioVideoFlowConfigurationRequested;
}
private static void IncomingCallOnAudioVideoFlowConfigurationRequested(object sender, AudioVideoFlowConfigurationRequestedEventArgs e)
{
AudioVideoFlow audioVideoFlow = e.Flow; // <--- There's your flow, gentleman.
}
Now, instead of registering for your incoming call, just call RegisterForIncomingCall(_userEndpoint);.
Your AVFlow will be hanging off e.Flow above, you could then pass that into your recorder: recorder.AttachFlow(e.Flow) or simply assign the flow to a field in your class and autoResetEvent.WaitOne(); and set that up where you're setting that up now.
Obviously this is a pretty naive implementation. A lot can go wrong in those few lines of code (exception handling/static event handler memory leak comes immediately to mind); don't forget to wire up events related to status changes on the conversation/call and endpoints, as well as any of the recovery related items.
I created some site columns / a content type and a list definition as part of a feature. I want to attach an eventreceiver to the content type. I added code to attach the event receiver to the content type. Using spmanager i can see that the event receiver is attached to the content type however when i create lists from the content type the event reciever is missing. Any ideas. My code is below
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
string asmName = System.Reflection.Assembly.GetExecutingAssembly().FullName;
string itemReceiverName = "xxxxxx.Intranet.SP.xxxxx.PermissionsUpdaterEventReceiver";
////surely a better way to get all lists than this
////re - do
using (SPSite thisSite = (SPSite)properties.Feature.Parent) {
using (SPWeb web = thisSite.RootWeb) {
SPContentType RambollNewsContentType = web.ContentTypes["RambollNewsContentType"];
RambollNewsContentType.EventReceivers.Add(SPEventReceiverType.ItemAdded, asmName, itemReceiverName);
RambollNewsContentType.Update(true);
}
}
}
I am using this successfully. I left in my logging and the logging method.
/// <summary>
/// This method is executed on feature activation.
/// It attaches the event receiver to the content type.
/// </summary>
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
LogMessage("FeatureActivated - Start");
SPSite site = (SPSite)properties.Feature.Parent;
LogMessage("FeatureActivated - 1");
SPWeb web = site.RootWeb;
LogMessage("FeatureActivated - 2");
//ListContentTypes(web);
SPContentType ctype = web.ContentTypes["Wells Project Task List"];
LogMessage("FeatureActivated - 3");
LogMessage("ctype name: " + ctype.Name.ToString());
if (ctype != null)
{
LogMessage("FeatureActivated - I have a content type. Web url: " + web.Url);
SPEventReceiverDefinition er = ctype.EventReceivers.Add();
er.Class = "Wells.SharePoint.ProjectManagementEventReceiver";
er.Assembly = "ProjectManagementEventReceiver, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a1cb21c41d80b7ae";
er.Type = SPEventReceiverType.ItemAdded;
er.Name = "ItemAdded";
er.SequenceNumber = 10001;
er.Update();
ctype.Update(false);
LogMessage("FeatureActivated - After ctype.update");
web.Dispose();
}
else
LogMessage("CT not found: " + web.Url);
LogMessage("FeatureActivated - End");
}
static void ListContentTypes(SPWeb web)
{
foreach (SPContentType ct in web.ContentTypes)
{
LogMessage("CT: " + ct.Name.ToString());
}
}
/// <summary>
/// This method is executed on feature deactivation.
/// It removes the event receiver from the content type
/// </summary>
/// <param name="properties"></param>
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
LogMessage("Feature DeActivated - Start");
SPSite site = (SPSite)properties.Feature.Parent;
SPWeb web = site.OpenWeb();
SPContentType contentType = web.ContentTypes["NAME OF CONTENT TYPE"];
if (contentType != null)
{
LogMessage("im have a content type. Web url: " + web.Url);
int i;
//Use the above integer to loop through the event recievers on the first list and delete the above assembly
for (i = 0; i < contentType.EventReceivers.Count; i++)
{
LogMessage("ER Count: " + contentType.EventReceivers.Count);
if (contentType.EventReceivers[i].Assembly.Contains("ProjectManagementEventReceiver"))
{
contentType.EventReceivers[i].Delete();
LogMessage("Deleting event receiver from CT");
}
}
contentType.Update();
}
else
LogMessage("CT not found: " + web.Url);
LogMessage("Feature DeActivated - End");
}
static void LogMessage(string msg)
{
StreamWriter wrtr = null;
try
{
wrtr = new StreamWriter("C:\\Logs\\FeatureActivatedDeactivated.txt", true);
wrtr.WriteLine(msg + "--[" + System.DateTime.Now.ToString() + "]" + Environment.NewLine);
wrtr.WriteLine(Environment.NewLine + "==================================");
}
catch (Exception e)
{
throw e;
}
finally
{
if (wrtr != null)
{
wrtr.Close();
wrtr.Dispose();
}
}
}
I am not sure is this related to your question or not but
but could you try to add the event receiver to the content type before you add the content type to the list.
I think the event receiver has to be added before because when adding a content type to a list the content type is not added directly to the list, rather a copy of it is added to the list. So when you add your content type to the list, there is no event receiver yet.
Correct me if i understand your question wrong?
Thanks
When I use the Java Bloomber V3 API it usually works. However, sometimes, especially after a reboot, bbcomm.exe is not running in the background. I can start it manually by running blp.exe, but I wondered if there was a way of doing this via the API?
After talking to the help desk, it turns out that on 64 bit Windows, running under a 64bit JVM bbcomm is not automatically started. This does not happen under 32bit Java - under 32 bit bbcomm automatically runs.
So my solutions are either to wait for the problem to be fixed by Bloomberg (now I understand it) or to check this specific case.
To check the specific case:
if running under a 64 bit windows (System property os.arch)
and if running under a 64bit JVM (System property java.vm.name)
then try and start a session
If this fails, assume bbcomm.exe is not running. Try to run bbcomm.exe using Runtime.exec()
I haven't tested the above yet. It may have exactly the same issues as Bloomberg have with 64bit VMs.
After spending some time with Help Help, it seems that bbcomm gets started either when you use the Excel API or run the API demo. But it does not get started automatically when called from the Java API. Possible ways to start it are:
adding an entry in the registry to automatically start bbcomm on startup: in HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run add a String value called bbcomm with value C:\blp\API\bbcomm.exe - but that opens a command window which remains visible, so not really an option (and if you close that window it terminates the bbcomm process)
create a batch file START /MIN C:\blp\API\bbcomm.exe and replace the entry in the registry with that (not tested) to call bbcomm silently
manually launch bbcomm from your java code as already suggested. As a reference, I post below the code that I'm using.
private final static Logger logger = LoggerFactory.getLogger(BloombergUtils.class);
private final static String BBCOMM_PROCESS = "bbcomm.exe";
private final static String BBCOMM_FOLDER = "C:/blp/API";
/**
*
* #return true if the bbcomm process is running
*/
public static boolean isBloombergProcessRunning() {
return ShellUtils.isProcessRunning(BBCOMM_PROCESS);
}
/**
* Starts the bbcomm process, which is required to connect to the Bloomberg data feed
* #return true if bbcomm was started successfully, false otherwise
*/
public static boolean startBloombergProcessIfNecessary() {
if (isBloombergProcessRunning()) {
logger.info(BBCOMM_PROCESS + " is started");
return true;
}
Callable<Boolean> startBloombergProcess = getStartingCallable();
return getResultWithTimeout(startBloombergProcess, 1, TimeUnit.SECONDS);
}
private static Callable<Boolean> getStartingCallable() {
return new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
logger.info("Starting " + BBCOMM_PROCESS + " manually");
ProcessBuilder pb = new ProcessBuilder(BBCOMM_PROCESS);
pb.directory(new File(BBCOMM_FOLDER));
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.toLowerCase().contains("started")) {
logger.info(BBCOMM_PROCESS + " is started");
return true;
}
}
return false;
}
};
}
private static boolean getResultWithTimeout(Callable<Boolean> startBloombergProcess, int timeout, TimeUnit timeUnit) {
ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "Bloomberg - bbcomm starter thread");
t.setDaemon(true);
return t;
}
});
Future<Boolean> future = executor.submit(startBloombergProcess);
try {
return future.get(timeout, timeUnit);
} catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
return false;
} catch (ExecutionException | TimeoutException e) {
logger.error("Could not start bbcomm", e);
return false;
} finally {
executor.shutdownNow();
try {
if (!executor.awaitTermination(100, TimeUnit.MILLISECONDS)) {
logger.warn("bbcomm starter thread still running");
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
ShellUtils.java
public class ShellUtils {
private final static Logger logger = LoggerFactory.getLogger(ShellUtils.class);
/**
* #return a list of processes currently running
* #throws RuntimeException if the request sent to the OS to get the list of running processes fails
*/
public static List<String> getRunningProcesses() {
List<String> processes = new ArrayList<>();
try {
Process p = Runtime.getRuntime().exec(System.getenv("windir") + "\\system32\\" + "tasklist.exe");
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
int i = 0;
while ((line = input.readLine()) != null) {
if (!line.isEmpty()) {
String process = line.split(" ")[0];
if (process.contains("exe")) {
processes.add(process);
}
}
}
} catch (IOException e) {
throw new RuntimeException("Could not retrieve the list of running processes from the OS");
}
return processes;
}
/**
*
* #param processName the name of the process, for example "explorer.exe"
* #return true if the process is currently running
* #throws RuntimeException if the request sent to the OS to get the list of running processes fails
*/
public static boolean isProcessRunning(String processName) {
List<String> processes = getRunningProcesses();
return processes.contains(processName);
}
}
In case someone needs help checking/starting bbcomm.exe process from the code hiding console window, this snippet is written in C#; I hope you can easily translate it to Java.
void Main()
{
var processes = Process.GetProcessesByName("bbcomm");
if (processes.Any())
{
Console.WriteLine(processes.First().ProcessName + " already running");
return;
}
var exePath = #"C:\blp\DAPI\bbcomm.exe";
var processStart = new ProcessStartInfo(exePath);
processStart.UseShellExecute = false;
processStart.CreateNoWindow = true;
processStart.RedirectStandardError = true;
processStart.RedirectStandardOutput = true;
processStart.RedirectStandardInput = true;
var process = Process.Start(processStart);
Console.WriteLine(process.ProcessName + " started");
}
bbcomm.exe is automatically started by the V3 API.