8058115: Some of MidiDeviceProviders do not follow the specification

Reviewed-by: prr, azvegint
This commit is contained in:
Sergey Bylokhov 2014-09-30 17:39:04 +04:00
parent 4ba0786cc0
commit 7a259eeb29
9 changed files with 186 additions and 65 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -117,7 +117,7 @@ public abstract class AbstractMidiDeviceProvider extends MidiDeviceProvider {
}
}
@Override
public final MidiDevice.Info[] getDeviceInfo() {
readDeviceInfos();
Info[] infos = getInfoCache();
@ -126,7 +126,7 @@ public abstract class AbstractMidiDeviceProvider extends MidiDeviceProvider {
return localArray;
}
@Override
public final MidiDevice getDevice(MidiDevice.Info info) {
if (info instanceof Info) {
readDeviceInfos();
@ -143,9 +143,7 @@ public abstract class AbstractMidiDeviceProvider extends MidiDeviceProvider {
}
}
}
throw new IllegalArgumentException("MidiDevice " + info.toString()
+ " not supported by this provider.");
throw MidiUtils.unsupportedDevice(info);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,9 +25,15 @@
package com.sun.media.sound;
import javax.sound.midi.*;
import java.util.ArrayList;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.Sequence;
import javax.sound.midi.Track;
// TODO:
// - define and use a global symbolic constant for 60000000 (see convertTempo)
@ -48,6 +54,17 @@ public final class MidiUtils {
private MidiUtils() {
}
/**
* Returns an exception which should be thrown if MidiDevice is unsupported.
*
* @param info an info object that describes the desired device
* @return an exception instance
*/
static RuntimeException unsupportedDevice(final MidiDevice.Info info) {
return new IllegalArgumentException(String.format(
"MidiDevice %s not supported by this provider", info));
}
/** return true if the passed message is Meta End Of Track */
public static boolean isMetaEndOfTrack(MidiMessage midiMsg) {
// first check if it is a META message at all

View File

@ -64,7 +64,7 @@ final class RealTimeSequencer extends AbstractMidiDevice
/**
* All RealTimeSequencers share this info object.
*/
static final RealTimeSequencerInfo info = new RealTimeSequencerInfo();
static final MidiDevice.Info info = new RealTimeSequencerInfo();
private static final Sequencer.SyncMode[] masterSyncModes = { Sequencer.SyncMode.INTERNAL_CLOCK };
@ -154,7 +154,7 @@ final class RealTimeSequencer extends AbstractMidiDevice
/* ****************************** CONSTRUCTOR ****************************** */
RealTimeSequencer() throws MidiUnavailableException {
RealTimeSequencer(){
super(info);
if (Printer.trace) Printer.trace(">> RealTimeSequencer CONSTRUCTOR");
@ -1088,7 +1088,7 @@ final class RealTimeSequencer extends AbstractMidiDevice
private static final String description = "Software sequencer";
private static final String version = "Version 1.0";
private RealTimeSequencerInfo() {
RealTimeSequencerInfo() {
super(name, vendor, description, version);
}
} // class Info

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,6 @@
package com.sun.media.sound;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.spi.MidiDeviceProvider;
/**
@ -36,23 +35,16 @@ import javax.sound.midi.spi.MidiDeviceProvider;
*/
public final class RealTimeSequencerProvider extends MidiDeviceProvider {
@Override
public MidiDevice.Info[] getDeviceInfo() {
MidiDevice.Info[] localArray = { RealTimeSequencer.info };
return localArray;
return new MidiDevice.Info[]{RealTimeSequencer.info};
}
public MidiDevice getDevice(MidiDevice.Info info) {
if ((info != null) && (!info.equals(RealTimeSequencer.info))) {
return null;
}
try {
@Override
public MidiDevice getDevice(final MidiDevice.Info info) {
if (RealTimeSequencer.info.equals(info)) {
return new RealTimeSequencer();
} catch (MidiUnavailableException e) {
return null;
}
throw MidiUtils.unsupportedDevice(info);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,11 +22,10 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.media.sound;
import java.util.Arrays;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiDevice.Info;
import javax.sound.midi.spi.MidiDeviceProvider;
/**
@ -36,17 +35,16 @@ import javax.sound.midi.spi.MidiDeviceProvider;
*/
public final class SoftProvider extends MidiDeviceProvider {
static final Info softinfo = SoftSynthesizer.info;
private static final Info[] softinfos = {softinfo};
@Override
public MidiDevice.Info[] getDeviceInfo() {
return Arrays.copyOf(softinfos, softinfos.length);
return new MidiDevice.Info[]{SoftSynthesizer.info};
}
public MidiDevice getDevice(MidiDevice.Info info) {
if (info == softinfo) {
@Override
public MidiDevice getDevice(final MidiDevice.Info info) {
if (SoftSynthesizer.info.equals(info)) {
return new SoftSynthesizer();
}
return null;
throw MidiUtils.unsupportedDevice(info);
}
}

View File

@ -31,6 +31,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -162,18 +163,11 @@ public class MidiSystem {
* of length 0 is returned.
*/
public static MidiDevice.Info[] getMidiDeviceInfo() {
List<MidiDevice.Info> allInfos = new ArrayList<>();
List<MidiDeviceProvider> providers = getMidiDeviceProviders();
for(int i = 0; i < providers.size(); i++) {
MidiDeviceProvider provider = providers.get(i);
MidiDevice.Info[] tmpinfo = provider.getDeviceInfo();
for (int j = 0; j < tmpinfo.length; j++) {
allInfos.add( tmpinfo[j] );
}
final List<MidiDevice.Info> allInfos = new ArrayList<>();
for (final MidiDeviceProvider provider : getMidiDeviceProviders()) {
Collections.addAll(allInfos, provider.getDeviceInfo());
}
MidiDevice.Info[] infosArray = allInfos.toArray(new MidiDevice.Info[0]);
return infosArray;
return allInfos.toArray(new MidiDevice.Info[allInfos.size()]);
}
/**
@ -187,17 +181,15 @@ public class MidiSystem {
* MIDI device installed on the system
* @see #getMidiDeviceInfo
*/
public static MidiDevice getMidiDevice(MidiDevice.Info info) throws MidiUnavailableException {
List<MidiDeviceProvider> providers = getMidiDeviceProviders();
for(int i = 0; i < providers.size(); i++) {
MidiDeviceProvider provider = providers.get(i);
public static MidiDevice getMidiDevice(final MidiDevice.Info info)
throws MidiUnavailableException {
for (final MidiDeviceProvider provider : getMidiDeviceProviders()) {
if (provider.isDeviceSupported(info)) {
MidiDevice device = provider.getDevice(info);
return device;
return provider.getDevice(info);
}
}
throw new IllegalArgumentException("Requested device not installed: " + info);
throw new IllegalArgumentException(String.format(
"Requested device not installed: %s", info));
}
/**

View File

@ -25,6 +25,8 @@
package javax.sound.midi.spi;
import java.util.Arrays;
import javax.sound.midi.MidiDevice;
/**
@ -45,16 +47,8 @@ public abstract class MidiDeviceProvider {
* @return {@code true} if the specified device is supported, otherwise
* {@code false}
*/
public boolean isDeviceSupported(MidiDevice.Info info) {
MidiDevice.Info infos[] = getDeviceInfo();
for(int i=0; i<infos.length; i++) {
if( info.equals( infos[i] ) ) {
return true;
}
}
return false;
public boolean isDeviceSupported(final MidiDevice.Info info) {
return Arrays.asList(getDeviceInfo()).contains(info);
}
/**

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.Collection;
import java.util.HashSet;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.spi.MidiDeviceProvider;
import static java.util.ServiceLoader.load;
/**
* @test
* @bug 8058115
* @summary MidiDeviceProvider shouldn't returns incorrect results or throw NPE
* in case of null MidiDevice.Info
* @author Sergey Bylokhov
*/
public final class NullInfo {
public static void main(final String[] args) {
// MidiSystem API
try {
MidiSystem.getMidiDevice(null);
throw new RuntimeException("IllegalArgumentException expected");
} catch (final MidiUnavailableException e) {
throw new RuntimeException("IllegalArgumentException expected", e);
} catch (final IllegalArgumentException ignored) {
// expected
}
// MidiDeviceProvider API
final Collection<String> errors = new HashSet<>();
for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) {
try {
if (mdp.isDeviceSupported(null)) {
throw new RuntimeException("null is supported");
}
final MidiDevice device = mdp.getDevice(null);
System.err.println("MidiDevice: " + device);
throw new RuntimeException("IllegalArgumentException expected");
} catch (final IllegalArgumentException e) {
errors.add(e.getMessage());
}
}
if (errors.size() != 1) {
throw new RuntimeException("Wrong number of messages:" + errors);
}
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.spi.MidiDeviceProvider;
import static java.util.ServiceLoader.load;
/**
* @test
* @bug 8058115
* @summary MidiDeviceProvider shouldn't returns incorrect results in case of
* unsupported MidiDevice.Info
* @author Sergey Bylokhov
*/
public final class UnsupportedInfo {
public static void main(final String[] args) {
final MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) {
for (final MidiDevice.Info info : infos) {
if (mdp.isDeviceSupported(info)) {
if (mdp.getDevice(info) == null) {
throw new RuntimeException("MidiDevice is null");
}
} else {
try {
mdp.getDevice(info);
throw new RuntimeException(
"IllegalArgumentException expected");
} catch (final IllegalArgumentException ignored) {
// expected
}
}
}
}
}
}