Use a .mid file in a .jar export - java

I'm working on a text-based RPG with some friends using Netbeans. It works all fine and dandy in Netbeans but when I export it to a .jar file I get this error.
Jan 28, 2019 2:27:15 PM Operator.DragonsHead startActionPerformed
SEVERE: null
java.io.FileNotFoundException: File "src\Operator\files\Opening.mid" does not exist!
This happens when the game starts, as we have a "theme" that plays at boot up.
The song plays on Netbeans but not when exported.
I'm relatively new to Java programming, I took a course on it last year.
I've tried looking around the web for people having the same issue, but I can't quite get it to duplicate with my code.
Here's the midi class:
import javax.sound.midi.*;
import java.io.File;
import java.io.IOException;
import java.io.FileNotFoundException;
public class MIDI {
private File file = null;
private Sequencer sequencer = null;
public MIDI (String midiFile) throws FileNotFoundException {
this.file = new File(midiFile);
if (!file.isFile()) {
throw new FileNotFoundException("File \"" + midiFile + "\" does not exist!");
}
try{
sequencer = MidiSystem.getSequencer();
if (sequencer == null){
System.err.println("Error: Sequencer not supported");
return;
}
sequencer.open();
Sequence sequence = MidiSystem.getSequence(file);
sequencer.setSequence(sequence);
}
catch (MidiUnavailableException | InvalidMidiDataException | IOException ex){
}
}
public void play(){
sequencer.start();
}
public void stop() {
sequencer.stop();
}
public void waitAndStop(int millis) {
Runnable song = () -> {
try {
Thread.sleep(millis);
}
catch (InterruptedException e) {
System.err.println("MIDI playback interrupted");
}
stop();
};
Thread t = new Thread(song);
t.start();
}
public long songLengthMicroseconds() {
return sequencer.getMicrosecondLength();
}
public Sequence getSequence(String resource) {
try {
return MidiSystem.getSequence(new File(resource));
}
catch (InvalidMidiDataException | IOException ex) {
return null;
}
}
}
Here's the lines that initialize it and call the song to play:
MIDI midiTest;
midiTest = new MIDI("src\\Operator\\files\\Opening.mid");
midiTest.play();

I'm not sure what the API is of 'MIDI', but unless you want to go through the rigamarole of writing an installer, you cannot use direct file access for resources like icons, pictures, music, and datafiles.
Instead, use the getResource/getResourceAsStream mechanism, which returns URLs/InputStreams. Well written libraries take these just as well as files.
Basic format:
try (InputStream resource = MyClassName.class.getResourceAsStream("Opening.mid")) {
// do something with resource here.
}
where Opening.mid is in the exact same place that MyClassName.class is (so, if you are shipping as a jar, it's in the jar, in the same folder structure as myClassName.class. If you prefer to have a root dir 'music' in your jar, you can pass for example: /music/Opening.mid, with the leading slash to indicate you're going off of the jar root.
secondary observation, if you don't know what to do with an exception, best solution is to add the exception(s) you cannot handle to your method's 'throws' line. If that is somehow not possible, the proper body for a catch block is:
throw new RuntimeException("unhandled checked exception", e);
because right now if an error occurs, your code will silently just keep going. If that was your intent (because, hey, music is optional I guess), I'd still log it SOMEWHERE, right now if an error occurs, you just won't know about it.

Related

Problems with loading a map with bukkit

I am trying to load a map with the bukkit API, and ran into a problem.
The map does not load. The file gets created and get cappied as well, but when i do /memory in game, it shows all the loaded worlds, and this does not show up. And when i try to teleport to the world by doing p.teleport(world.getSpawnLocation()); it just throws a java.lang.NullPointerException: null execption.
my code:
public static void loadMap(String l) throws IOException {
try {
File folderName = new File(plugin.getDataFolder() + "/maps/Dungeon");
File desti = new File(l + "_world");
if(!desti.exists()) {
desti.mkdir();
}
FileUtils.copyDirectory(folderName, desti);
World world = Bukkit.getServer().createWorld(new WorldCreator(l + "_world"));
System.out.println("[DDEBUG]" + world);
} catch (Exception e) {
System.out.println(e);
}
}
Any ideas on how to fix this ?
that means the player is null, so it throws this error
btw. if you use try and catch blok, so remove throws IOException

Resource is not grabbed when exporting to .JAR

I'm trying to get a better understanding of Java by creating a small 2D game. I feel like the best way to learning is by struggling, so I try not to get help on any problems I have; I just solve them myself. However, I've tried almost everything any I can't get my background music to play in my exported version of my game. All the images work and everything else pulled using the " getClass()" method works, but the music doesn't.
Sorry I have to put all of the code from my BackgroundMusicManager class, but because I want to do things without help, my first version of my programs are usually very messy and require a lot of optimization. In short, you kinda have to see where things are called and initialized and whatnot to really see how the things work.
package com.cs.dd.audioManager;
import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import javax.sound.sampled.*;
import com.nickgirga.dd.main.*;
import sun.applet.Main;
public class BackgroundMusicManager implements Runnable {
//URLs
public URL mmBgMusicURL = getClass().getResource("/audio/backgroundMusic/casual.wav");
//Files
public File[] bgMusics = { new File(mmBgMusicURL.getFile()) };
public File bgMusic = bgMusics[0];
private static Clip clip;
public static int newGameState;
public static boolean enabled = true;
public static boolean asPlaying = false;
public static Thread bgMusicPlayer = new Thread(new BackgroundMusicManager());
public void play () {
if (enabled) {
try {
if (bgMusic != null) clip = AudioSystem.getClip();
if (bgMusic != null) clip.open(AudioSystem.getAudioInputStream(bgMusic));
if (bgMusic != null) clip.start();
//System.out.println(bgMusics[0].getAbsolutePath());
loopChecker();
bgMusicPlayer.wait();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (Exception e) {
//e.printStackTrace();
}
}
}
public void loopChecker () {
while (true) {
if (clip.getMicrosecondPosition() >= clip.getMicrosecondLength()) {
bgMusicPlayer.notify();
}
if (!(GameState.state == newGameState)) {
setClip();
}
}
}
public void setClip () {
//System.out.println("setClip");
newGameState = GameState.state;
if (GameState.state == 0) {
clip.stop();
bgMusic = bgMusics[0];
bgMusicPlayer.notify();
} else {
if (GameState.state == 1) {
clip.stop();
bgMusic = bgMusics[0];
bgMusicPlayer.notify();
} else {
clip.stop();
bgMusic = null;
bgMusicPlayer.notify();
}
}
}
#Override
public void run() {
while (true) {
play();
}
}
}
After exporting this as a JAR with the libraries packed into it, the console reads:
java.io.FileNotFoundException: audio\backgroundMusic\casual.wav (The system cannot find the path specified)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(Unknown Source)
at java.io.FileInputStream.<init>(Unknown Source)
at com.sun.media.sound.WaveFloatFileReader.getAudioInputStream(Unknown Source)
at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
at com.cs.dd.audioManager.BackgroundMusicManager.play(BackgroundMusicManager.java:33)
at com.cs.dd.audioManager.BackgroundMusicManager.run(BackgroundMusicManager.java:89)
at java.lang.Thread.run(Unknown Source)
I extracted the JAR and found the file exactly where the FileNotFoundException points, so I'm left very confused. The audio works while running in Eclipse. The images still show in the export. Why will it work with the images, but not the audio?
Any help is very appreciated! Thank you!!!
Instead of
getClass().getResource("/audio/backgroundMusic/casual.wav");
use
getClass().getClassLoader().getResourceAsStream("/audio/backgroundMusic/casual.wav")
In this way it will look from the root, not from the path of the current invoking class

How to programmaticaly (java) obtain JBoss info and manage it?

Hi i want to obtain from java classes infos on JBoss like the status and the version and then manage him by starting/stopping/resatring him.
For the version i do this :
String fileSeparator = System.getProperty("file.separator");
String runJarFile = jbossHomeDir + fileSeparator + "bin" + fileSeparator + "run.jar";
System.out.println("JBOSSDIR est :" + runJarFile);
jarInputStream = new JarInputStream(new FileInputStream(runJarFile));
System.out.println("Pigmalion" + jarInputStream.getNextEntry().getName());
Manifest manifest = jarInputStream.getManifest();
Attributes attributes = manifest.getMainAttributes();
jbossVersion = attributes.getValue(Attributes.Name.SPECIFICATION_VERSION);
which works fine, now for the status, i saw some people doing it by checking the port, but isn't there another way of doing it ?
As for the start/stop/restart commands i saw this script
package com.sudipta.jboss.conf;
import org.jboss.Main;
public class JbossOperation {
public static Main ob;
static Class jbossMain;
static{
try {
jbossMain=Class.forName("org.jboss.Main");
ob = (Main)jbossMain.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* START JBOSS SERVER
* #return true if started successfully
*/
public static boolean startServer(){
boolean status=true;
String str[]={"-c","default"};
try {
ob.boot(str);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return status;
}
/**
* STOP JBOSS SERVER
* #return true if started successfully
*/
public static boolean stopServer(){
boolean status=true;
try {
ob.shutdown();
} catch (Throwable e) {
e.printStackTrace();
}
return status;
}
/**
* Main method
* #param args
*/
public static void main(String args[]){
System.out.println("---------------------Strating the server------------------");
startServer();
System.out.println("---------------------Stoping the server------------------");
stopServer();
System.out.println("---------------------SERVER STOPPED------------------");
}
}
I downloaded the jboss-system 4.0.2 jar and it tells me the shutdown method doesn't exist. Do i have to download other jboss jars ?
If you are looking for something more enterprisy (but still open source). You may want to use RHQ for it. It allows to run operations on managed resources and it can start/restart/stop JBoss server, deploy a war to it and far more. But the learning curve may be quite steep.
Have you considered to use JMX Console?. Moreover, if you really need to manage the server from a Java program you could write a JMX client that invoke specific server operations like shutdown. Additionaly, different kind of server information can be obtained this way. (ofcourse JMX wont be useful for start the server).

Restarting Java Application

How can I introduce automatic updates and restart feature in Java Swing applications.
Also I needed to roll back to previous versions.
I have made a application jar file and launcher jar file, which launches the application jar file.
This attempt was successful. But I can not integrate these two jar files, when creating a installer for MacOSX.
The Launcher class as follows:
public class Launcher {
private final Logger logger = Logger.getLogger(Launcher.class.getName());
private String getVersionNumber() throws IOException {
try {
JarFile runningJarFile = new JarFile(new File("Application.jar"));
String versionNumber = runningJarFile.getManifest()
.getMainAttributes().getValue("Bundle-Version");
runningJarFile.close();
logger.log(
Level.SEVERE,
new StringBuilder()
.append("The version number of existing Application.jar file is ")
.append(versionNumber).toString());
return versionNumber;
} catch (IOException e) {
logger.log(
Level.SEVERE,
new StringBuilder()
.append("Could not read the version number from existing Application.jar")
.append(Arrays.toString(e.getStackTrace()))
.toString());
throw new IOException(e);
}
}
private void updateApplication() {
try {
File updateDirectory = new File("Update");
if (updateDirectory.isDirectory()) {
if (updateDirectory.list(new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
return name.startsWith("\\.");
}
}).length > 0) {
String versionNumber = getVersionNumber();
logger.log(
Level.SEVERE,
new StringBuilder()
.append("A new update is available. Rename the existing Application.jar to ")
.append(versionNumber)
.append(".jar")
.append(" and rename the new_Application.jar to Application.jar")
.toString());
File Application = new File("Application.jar");
Application.renameTo(new File(new StringBuilder()
.append(versionNumber).append(".jar").toString()));
File newApplication = new File("Update/new_Application.jar");
newApplication.renameTo(new File("Application.jar"));
newApplication.delete();
}
}
} catch (Exception e) {
logger.log(Level.SEVERE,
new StringBuilder().append("Could not update Application")
.append(Arrays.toString(e.getStackTrace()))
.toString());
}
}
private void launchApplication() {
try {
logger.log(Level.SEVERE, "Lauching Application.jar");
ProcessBuilder pb = new ProcessBuilder("Java", "-jar", "Application.jar");
pb.start();
} catch (IOException e) {
logger.log(Level.SEVERE,
new StringBuilder().append("Could not launch Application.jar ")
.append(Arrays.toString(e.getStackTrace()))
.toString());
}
}
private void quitLauncher() {
logger.log(Level.SEVERE, "Launcher is exiting");
System.exit(0);
}
private void startApplication() {
updateApplication();
launchApplication();
quitLauncher();
}
public static void main(String[] args) {
Launcher launcher = new Launcher();
launcher.startApplication();
}
}
Thanks
First of all, are you creating a standard installer package (mpkg or pkg)?
You should make the launcher download the update, and then execute it (with /usr/sbin/installer ). After that, the installer should have a postflight/postinstall/postprocessing script that kills any app with the name of yours (this can be as tricky as looking for a process with a given name..), and then launches the recently installed app.
This makes that your app will be launched even, after the first install (you may avoid this making it check if it is an update or not -saving a marker file from the Launcher "updating.txt" may suffice- )
Here is a full guide of how to create installer packages (almost form scratch): Making OS X Installer Packages like a Pro - Xcode Developer ID ready pkg
Or well, you may use this cool tool: http://s.sudre.free.fr/Software/Packages/about.html
I expect this all is not an overkill for what are you looking for.

Find the directory for a FileStore

I'm trying to find a way to detect when a flash drive has been plugged into my computer. So far, the solution I found was to poll FileSystem#getFileStores for changes. This does indeed tell me when the flash drive has been inserted, but as far as I can tell there is no way to retrieve the location for it. FileStore#type and FileStore#name both seem highly unreliable as their return value is implementation specific, but they appear to be the only methods that might return any relevant information that might help find the directory for the FileStore.
With that in mind, the following code:
public class Test {
public static void main(String[] args) throws IOException {
for (FileStore store : FileSystems.getDefault().getFileStores()) {
System.out.println(store);
System.out.println("\t" + store.name());
System.out.println("\t" + store.type());
System.out.println();
}
}
}
Gave me this output:
/ (/dev/sda5)
/dev/sda5
ext4
/* snip */
/media/TI103426W0D (/dev/sda2)
/dev/sda2
fuseblk
/media/flashdrive (/dev/sdb1)
/dev/sdb1
vfat
As it turns out, FileStore#type returns the format of the drive and FileStore#name returns the location of the device file for the drive. As far as I can tell, the only method which has the location of the drive is the toString method, but extracting the path name out of it seems dangerous because I'm not sure how well that particular solution would hold up on other operating systems and future versions of Java.
Is there something I'm missing here or is this simply not possible purely with Java?
System Information:
$ java -version
java version "1.7.0_03"
OpenJDK Runtime Environment (IcedTea7 2.1.1pre) (7~u3-2.1.1~pre1-1ubuntu2)
OpenJDK Client VM (build 22.0-b10, mixed mode, sharing)
$ uname -a
Linux jeffrey-pc 3.2.0-24-generic-pae #37-Ubuntu SMP Wed Apr 25 10:47:59 UTC 2012 i686 athlon i386 GNU/Linux
Here's a temporary work around until a better solution is found:
public Path getRootPath(FileStore fs) throws IOException {
Path media = Paths.get("/media");
if (media.isAbsolute() && Files.exists(media)) { // Linux
try (DirectoryStream<Path> stream = Files.newDirectoryStream(media)) {
for (Path p : stream) {
if (Files.getFileStore(p).equals(fs)) {
return p;
}
}
}
} else { // Windows
IOException ex = null;
for (Path p : FileSystems.getDefault().getRootDirectories()) {
try {
if (Files.getFileStore(p).equals(fs)) {
return p;
}
} catch (IOException e) {
ex = e;
}
}
if (ex != null) {
throw ex;
}
}
return null;
}
As far as I know, this solution will only work for Windows and Linux systems.
You have to catch the IOException in the Windows loop because if there is no CD in the CD drive an exception is thrown when you try to retrieve the FileStore for it. This might happen before you iterate over every root.
This is what I have ended up doing. This is limited to Windows + UNIX but avoids using external tools or additional library calls. It steals the information Java already has in the FileStore objects
LinuxFileStore definitely extends UnixFileStore, so it will work. Same deal for Solaris. Since Mac OS X is UNIX, it probably works there but I'm not sure because I couldn't see its subclass in any place I was looking.
public class FileStoreHacks {
/**
* Stores the known hacks.
*/
private static final Map<Class<? extends FileStore>, Hacks> hacksMap;
static {
ImmutableMap.Builder<Class<? extends FileStore>, Hacks> builder =
ImmutableMap.builder();
try {
Class<? extends FileStore> fileStoreClass =
Class.forName("sun.nio.fs.WindowsFileStore")
.asSubclass(FileStore.class);
builder.put(fileStoreClass, new WindowsFileStoreHacks(fileStoreClass));
} catch (ClassNotFoundException e) {
// Probably not running on Windows.
}
try {
Class<? extends FileStore> fileStoreClass =
Class.forName("sun.nio.fs.UnixFileStore")
.asSubclass(FileStore.class);
builder.put(fileStoreClass, new UnixFileStoreHacks(fileStoreClass));
} catch (ClassNotFoundException e) {
// Probably not running on UNIX.
}
hacksMap = builder.build();
}
private FileStoreHacks() {
}
/**
* Gets the path from a file store. For some reason, NIO2 only has a method
* to go in the other direction.
*
* #param store the file store.
* #return the path.
*/
public static Path getPath(FileStore store) {
Hacks hacks = hacksMap.get(store.getClass());
if (hacks == null) {
return null;
} else {
return hacks.getPath(store);
}
}
private static interface Hacks {
Path getPath(FileStore store);
}
private static class WindowsFileStoreHacks implements Hacks {
private final Field field;
public WindowsFileStoreHacks(Class<?> fileStoreClass) {
try {
field = fileStoreClass.getDeclaredField("root");
field.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new IllegalStateException("file field not found", e);
}
}
#Override
public Path getPath(FileStore store) {
try {
String root = (String) field.get(store);
return FileSystems.getDefault().getPath(root);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Denied access", e);
}
}
}
private static class UnixFileStoreHacks implements Hacks {
private final Field field;
private UnixFileStoreHacks(Class<?> fileStoreClass) {
try {
field = fileStoreClass.getDeclaredField("file");
field.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new IllegalStateException("file field not found", e);
}
}
#Override
public Path getPath(FileStore store) {
try {
return (Path) field.get(store);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Denied access", e);
}
}
}
}
I've not really explored this area of java, but I found this, which seems to be related. It uses File.listRoots()
There also seems to be a number of related questions linked there too.
This works for Windows:
public Path getFileStoreRootPath(FileStore fs) throws Exception {
for (Path root : FileSystems.getDefault().getRootDirectories()) {
if (Files.isDirectory(root) && Files.getFileStore(root).equals(fs)) {
return root;
}
}
throw new RuntimeException("Root directory for filestore " + fs + " not found");
}
Basically, by filtering by condition Files.isDirectory(root) we are excluding all CD/DVD drives which will throw IOException when compact-disc is not inserted.

Categories