Both the systems described are Windows XP with Lotus Notes 8.5.
I have a Java app (sample code below) that uses notes.jar to interact with Lotus Notes. The app works fine on a system that has notes.ini in the Lotus install dir of c:\Program Files\Lotus\Notes and the user ID file is in c:\Program Files\Lotus\Notes\Data. The user has to type a password to login to Lotus. This system has HKLM\Software\Lotus\Notes\MultiUser set to 0 (single user system). On this machine, the below code displays good values on the four println’s.
On a problem system, this app prints the four headings but blanks for the four values (the user name, key filename, mailfile, and mailserver are all blank). This problem system has notes.ini and the user ID file in D:\Data\johnsmith\NotesData. Lotus is installed in C:\Program Files\Lotus\Notes. This problem system also has HKLM\Software\Lotus\Notes\MultiUser set to 1 (implying it is multiuser instead of single user). Finally, under Lotus’s File -> Security -> User Security dialog the "Log in to Notes using your operating system login" box is checked (so the user doesn’t type in a password to login to Lotus).
So, it appears that on the problem system, the notes.ini file can’t be found (since notes.ini is where the four output values are supposed to be read from). I’ve looked through the Notes.jar API and can’t see any way to specify the location of notes.ini. The dir where notes.ini resides is in the Windows PATH, but that doesn’t help.
Any help would be appreciated.
import java.io.*;
import lotus.domino.*;
public static void main(String[] args) throws IOException {
try {
NotesThread.sinitThread();
Session session = NotesFactory.createSession();
System.out.println("Common user name: " + session.getCommonUserName());
System.out.println("KeyFilename: " + session.getEnvironmentString("KeyFilename", true));
System.out.println("MailFile: " + session.getEnvironmentString("MailFile", true));
System.out.println("MailServer: " + session.getEnvironmentString("MailServer", true));
} catch (Exception ex) {
ex.printStackTrace();
} finally {
NotesThread.stermThread();
}
}
As mentioned in the original question, if HKEY_LOCAL_MACHINE\Software\Lotus\Notes\MultiUser has a value of 1, then you have a multi-user installation (even if you are the only user of Lotus).
Here is a solution that worked. Find the location of Notes.ini, probably somewhere like C:\Documents and Settings\(username)\Lotus. Edit or create the string value below and set it to your Notes.ini directory. HKEY_CURRENT_USER\Software\Lotus\Notes\(optional-version)\NotesIniPath.
In a multi-user environment, Lotus Notes gets the ini filename from the NotesIniPath registry value.
Add a new command-line parameter, "=c:\data\johnsmith\NotesData\notes.ini" . To make this happen, you need to use NotesFactory.CreateSession(String host, String args[], String user, String passwd); method, after setting up a new String array containing that parameter and whatever other arguments were passed, since itis basically supposed to be the String args[] as passed to static Main. (The =fullpath\notes.ini parameter just needs to be in the array, it doesn't need to be in any specific location.)
This permits the session to be initialized with the absolute path to the notes.ini file used, and appears to be supported since (though I could be wrong) Notes 5.0.5.
Notably, the Directory= line is going to be taken from that notes.ini and used for all error reporting and logging, as the user's private data directory.
There is a number of things you can try:
Notes actually comes with its own JVM and I found using this JVM makes Java applications run more reliably with Notes classes since any eventually needed support library would be properly configured.
What happens if notes is already running before you start your program. There are 2 variations here: Checkbox "Don't prompt for a password from other Notes-based programs" is checked or unchecked.
Make sure to switch to the directory where the Notes.ini is at home before you run the app. (And verify that the user can't see any other notes.ini variables)
Related
I'm trying to write to a file located in my $HOME directory. The code to write to that file has been packaged into a jar file. When I run the unit tests to package the jar file, everything works as expected - namely the file is populated and can be read from again.
When I try to run this code from another application where the jar file is contained the lib directory it fails. The file is created - but the file is never written to. When the app goes to read the file it fails parsing it because it is empty.
Here is the code that writes to the file:
logger.warn("TestNet wallet does not exist creating one now in the directory: " + walletPath)
testNetFileName.createNewFile()
logger.warn("Wallet file name: " + testNetFileName.getAbsolutePath)
logger.warn("Can write: "+ testNetFileName.canWrite())
logger.warn("Can read: " + testNetFileName.canRead)
val w = Wallet.fromWatchingKey(TestNet3Params.get(), testNetSeed)
w.autosaveToFile(testNetFileName, savingInterval, TimeUnit.MILLISECONDS, null)
w
}
here is the log form the above method that is relevant:
2015-12-30 15:11:46,416 - [WARN] - from class com.suredbits.core.wallet.ColdStorageWallet$ in play-akka.actor.default-dispatcher-9
TestNet wallet exists, reading in the one from disk
2015-12-30 15:11:46,416 - [WARN] - from class com.suredbits.core.wallet.ColdStorageWallet$ in play-akka.actor.default-dispatcher-9
Wallet file name: /home/chris/testnet-cold-storage.wallet
then it bombs.
Here is the definition for autoSaveToFile
public WalletFiles autosaveToFile(File f, long delayTime, TimeUnit timeUnit,
#Nullable WalletFiles.Listener eventListener) {
lock.lock();
try {
checkState(vFileManager == null, "Already auto saving this wallet.");
WalletFiles manager = new WalletFiles(this, f, delayTime, timeUnit);
if (eventListener != null)
manager.setListener(eventListener);
vFileManager = manager;
return manager;
} finally {
lock.unlock();
}
}
and the definition for WalletFiles
https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/wallet/WalletFiles.java#L68
public WalletFiles(final Wallet wallet, File file, long delay, TimeUnit delayTimeUnit) {
// An executor that starts up threads when needed and shuts them down later.
this.executor = new ScheduledThreadPoolExecutor(1, new ContextPropagatingThreadFactory("Wallet autosave thread", Thread.MIN_PRIORITY));
this.executor.setKeepAliveTime(5, TimeUnit.SECONDS);
this.executor.allowCoreThreadTimeOut(true);
this.executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
this.wallet = checkNotNull(wallet);
// File must only be accessed from the auto-save executor from now on, to avoid simultaneous access.
this.file = checkNotNull(file);
this.savePending = new AtomicBoolean();
this.delay = delay;
this.delayTimeUnit = checkNotNull(delayTimeUnit);
this.saver = new Callable<Void>() {
#Override public Void call() throws Exception {
// Runs in an auto save thread.
if (!savePending.getAndSet(false)) {
// Some other scheduled request already beat us to it.
return null;
}
log.info("Background saving wallet, last seen block is {}/{}", wallet.getLastBlockSeenHeight(), wallet.getLastBlockSeenHash());
saveNowInternal();
return null;
}
};
}
I'm guessing it is some sort of permissions issue but I cannot seem to figure this out.
EDIT: This is all being run on the exact same Ubuntu 14.04 machine - no added complexity of different operating systems.
You cannot generally depend on the existence or writability of $HOME. There are really only two portable ways to identify (i.e. provide a path to) an external file.
Provide an explicit path using a property set on the invocation command line or provided in the environment, or
Provide the path in a configuration properties file whose location is itself provided as a property on the command line or in the environment.
The problem with using $HOME is that you cannot know what userID the application is running under. The user may or may not even have a home directory, and even if the user does, the directory may or may not be writable. In your specific case, your process may have the ability to create a file (write access on the directory itself) but write access to a file may be restricted by the umask and/or ACLs (on Windows) or selinux (on Linux).
Put another way, the installer/user of the library must explicitly provide a known writable path for your application to use.
Yet another way to think about it is that you are writing library code that may be used in completely unknown environments. You cannot assume ANYTHING about the external environment except what is in the explicit contract between you and the user. You can declare in your interface specification that $HOME must be writable, but that may be highly inconvenient for some users whose environment doesn't have $HOME writable.
A much better and portable solution is to say
specify -Dcom.xyz.workdir=[path] on the command line to indicate the work path to be used
or
The xyz library will look for its work directory in the path specified by the XYZ_WORK environment variable
Ideally, you do BOTH of these to give the user some flexibility.
savePending is always false. In the beginning of call you check that it is false, and return null. The actual save code is never executed. I am guessing you meant to check if it was true there, and also set it to true, not false. You then also need to reset it back to false in the end.
Now, why this works in your unit test is a different story. The test must be executing different code.
I am currently migrating an Eclipse 3.0 application to 4.4. The user data was and still should be stored in the folder C:\Users\username\AppData\Roaming\applicationname
The application is using following code to read the directory:
public static String getUserDirectory()
{
String directory = InternalPlatform.getDefault().getUserLocation().getFile();
return directory;
}
I know the code is deprecated, but following code returns the same:
public static String getUserDirectory()
{
String directory = Platform.getUserLocation().getURL().getFile();
return directory;
}
They both return C:\Users\username\user but as I said the user data should be stored at C:\Users\username\AppData\Roaming\applicationname. Did the behaviour of those methods change?
How can I realize that I store my user data under C:\Users\username\AppData\Roaming\applicationname and my application can still find the directory?
I know this has to do something with environment-variables which I don't fully understand.
I don't have a 3.x target platform at hand to compare but C:\Users\username\user looks plain wrong.
If you are interested in the details, the constructor of EquinoxLocations computes the userLocation and adds the literal 'user' the the user's home directory if no default is specified.
Hence, if you start your application with -user #user.home or -Dosgi.user.area=#user.home, the user location will be set to C:\Users\username\. Still not what you are looking for, but at least a sane value.
I think this is a bug in Equinox and recommend to file a bugzilla. If it turns out that there is a good reason for this appraoch the bug entry will still serve as documentation/reasoning.
In the meanwhile you could obtain the home directory on Windows through System.getenv( "APPDATA" ). According to this post it will return the roaming home directory.
I solved the problem by adding three properties in the Configuration tab of my config.ini.product-file:
osgi.configuration.area =
#user.home/AppData/Roaming/ApplicationName/...
osgi.user.area =
#user.home/AppData/Roaming/ApplicationName/...
osgi.instance.area =
#user.home/AppData/Roaming/ApplicationName
Now my method as stated in my question reads the paths that are configured by those properties and the config.ini file which is generated looks exactly like the one of the old build with Eclipse 3.0.
I want to know whether the user launched our Java-based application from a read-only file system like from a .dmg, so functions like auto-update will be able to show meaningful information instead of aborting with an error. I first thought checking the .app's path would be sufficient (when launched from a .dmg it is something like /Volumes/MyApp 1.2.3/MyApp.app, but this won't work, because the user might have installed the application on a different partition. What other things may I check?
You can use -[NSURL getResourceValue:forKey:error:] with the key NSURLVolumeIsReadOnlyKey. You would apply this to the app bundle URL as returned by [[NSBundle mainBundle] bundleURL]. So:
NSBundle* bundle = [NSBundle mainBundle];
NSURL* bundleURL = bundle.bundleURL;
NSNumber* readOnly;
NSError* error;
if ([bundleURL getResourceValue:&readOnly forKey:NSURLVolumeIsReadOnlyKey error:&error])
{
BOOL isReadOnly = [readOnly boolValue];
// act on isReadOnly value
}
else
{
// Handle error
}
If OSX is POSIX compliant, to determine if filesystem is mounted R/O, You can use statvfs() or fstatvfs(), returned struct statvfs field f_flag should have ST_RDONLY bit set for R/O filesystem.
As it was pointed in comments, check if this information is correctly provided by OS.
JNA and this question may be usefull for Java.
A few more ideas, which may be usefull here (access(), open(), utime() ).
OS X specific statfs() may be used too, but this function is not portable (Linux and *BSD have slightly different statfs() functions).
You can also check directly from Java whether a certain path points to something within a read-only directory by querying the FileStore associated with your path:
File classpathRoot = new File(MyClass.class.getClassLoader().getResource("").getPath());
/* getPath() actually returns a String instead of a Path object,
* so we need to take this little detour */
Path yourAppPath = classpathRoot.toPath();
boolean isReadOnly = Files.getFileStore(yourAppPath).isReadOnly();
I'm setting up a form on my website. I want the PHP code that handles emailing info about the form to me to also run a java program printing information about it. Here is my PHP code
$name = $_POST['name'];
$email_address = $_POST['email'];
$date = $_POST['date'];
$time = $_POST['time'];
$message = $_POST['message'];
$info = array($name, $email_address, $date, $time, $message);
exec('java -jar "C:\SomePathTo\HelloWorld.jar" $info 2>&1' , $output);`
var_dump($output);
And my Java code
public class HelloWorld {
public static void main(String[] args) {
for(int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
When my website runs this code I get the following output/error message
array(1) { [0]=> string(197) "Error: Unable to access jarfile C:\SomePathTo\HelloWorld.jar" }
Help!
Obviously, the backslash escaping is not a problem, for the error message lists correct backslashes. If the problem was about backslashes, this would not be the case. (You used single quotes, which strips backslashes of their special meaning.)
Furthermore, we can notice that whatever generated the error message knows that it is looking for a "jarfile". What, in your stack, does that? It is not PHP; it is not the operating system's kernel. Apparently, you are getting Java VM to run. That's probably a good thing.
Why can't the Java VM access your jar file? You might have misspelt its name, but this would be something so obvious that it would have come up when you double-checked the code. It is more likely that this happens because the jar file is somewhere deep in your home directory (I can conclude "deep" from the fact that when you sanitised the filename, you kept the error message's length of 197) where the user context of the Java VM can't read. As you're running PHP through a web server, this would be determined by your web server's configuration, but it is fairly common to have a dedicated user account named something like "www-data" or "Internet Scripts" under which the code runs. You should find out which it is on your system.
Once that has been done, you have a few options. You can grant the user running your PHP (and in this context, Java VM) read access to the jar file. As soon as your jar file wants to access other files, you'll also need to let that user account to access those files, too. (Just make sure it can't overwrite or delete anything important.) Alternatively, you could reconfigure your web server (or ask your web server's administrator to it) so that it would run scripts written by you in your user context.
As above.
I have scoured the web, i also rang mac support and annoyed a mac (OSX Lion) genius (out of desperation).
I have no idea how to do this, I really don't want to have to sit on top of a terminal and give it commands.
Has any one encountered this or got a solution?
Try looking at Greg Guerin's AuthKit library. It is a Mac-specific library that wraps Mac OS X Authorization Services.
Here is an example:
import glguerin.authkit.*;
Privilege priv = new Privilege("system.privilege.admin");
Authorization auth = new MacOSXAuthorization();
try
{
// This will cause an authentication prompt to be
// shown to the user, requesting the "system.privilege.admin"
// privilege.
auth.authorize(priv, true);
// If we reach this point, we can execute privileged programs.
// Load the secured file.
Process proc = auth.execPrivileged(new String[] { "/bin/cat", "/root/securefile" });
InputStream inputStream = proc.getInputStream();
// Use standard I/O mechanisms to read the input.
}
catch (UnauthorizedCancellation e)
{
// User chose not to authorize the application.
// Handle appropriately.
}
The auth.authorize() call will cause the standard "Please enter your password to allow program X to make changes" dialog. The user can cancel if desired, causing glguerin.authkit.UnauthorizedCancellation to be thrown.
This solution has a huge advantage over using sudo or setuid: it only runs the necessary tasks as root.
One last gotcha: the default JNI loader for AuthKit uses the Cocoa/Java bridge, which was removed from Mac OS X as of Snow Leopard. So on recent versions of Mac OS X, the code above will fail with UnsatisfiedLinkError. To work around this, use the following:
// Put this class somewhere:
public class AuthKitLibLoader extends LibLoader
{
#Override
protected File makeFallbackDir()
{
return new File(".");
}
}
// Then, before calling AuthKit (using the above example), do this:
// Hook in our "Snow Leopard-safe" extension to AuthKit (see below).
System.setProperty("glguerin.util.LibLoader.imp", AuthKitLibLoader.class.getName());
Finally, be sure to read the AuthKit documentation for more detail.
If you run the application as the root user, the application will have full access to everything.
This is a dangerous operation however because it gives the application full privileges.
Another option would be to run it as a user that has the needed permissions to the files in question. This can be done by putting the user or the files in the appropriate group.
You probably need to SETUID the application to root.
> su
Enter password:
> chown root:wheel myJavaApp
> chmod ug+s myJavaApp
> exit
Now whenever someone in the wheel group runs myJavaApp, it will run as its owner (root). Just make sure you're in the wheel group (or whatever other group)
Alternatively, you could chmod a+s myJavaApp ... but that would let ANYONE AT ALL run the program as root. I would think carefully about that.