1 package org.libvirt; 2 3 import org.libvirt.jna.Libvirt; 4 import org.libvirt.jna.LibvirtQemu; 5 import org.libvirt.jna.Libvirt.VirEventTimeoutCallback; 6 import org.libvirt.jna.CString; 7 import static org.libvirt.ErrorHandler.processError; 8 9 import com.sun.jna.Native; 10 import com.sun.jna.Pointer; 11 import com.sun.jna.ptr.LongByReference; 12 13 import java.util.concurrent.atomic.AtomicBoolean; 14 import java.util.concurrent.atomic.AtomicInteger; 15 16 /** 17 * This class represents an instance of the JNA mapped libvirt 18 * library. 19 * 20 * The library will get loaded when first accessing this class. 21 * 22 * Additionally, this class contains internal methods to ease 23 * implementing the public API. 24 */ 25 public final class Library { 26 private static AtomicBoolean runLoop = new AtomicBoolean(); 27 private static AtomicInteger timerID = new AtomicInteger(-1); 28 private static VirEventTimeoutCallback timer = new VirEventTimeoutCallback() { 29 @Override 30 public void tick(final int id, final Pointer p) { 31 // disable myself again right after being triggered 32 libvirt.virEventUpdateTimeout(id, -1); 33 } 34 }; 35 36 static final Libvirt libvirt; 37 static final LibvirtQemu libvirtQemu; 38 39 // an empty string array constant 40 // prefer this over creating empty arrays dynamically. 41 static final String[] NO_STRINGS = {}; 42 43 // Load the native part 44 static { 45 libvirt = Libvirt.INSTANCE; 46 try { libvirt.virInitialize()47 processError(libvirt.virInitialize()); 48 } catch (Exception e) { 49 e.printStackTrace(); 50 } 51 try { 52 libvirtQemu = getVersion() > 9010 ? LibvirtQemu.INSTANCE : null; 53 } catch (LibvirtException e) { 54 throw new RuntimeException("libvirt error get version", e); 55 } 56 } 57 Library()58 private Library() {} 59 60 /** 61 * Returns the version of the native libvirt library. 62 * 63 * @return major * 1,000,000 + minor * 1,000 + release 64 * @throws LibvirtException 65 */ getVersion()66 public static long getVersion() throws LibvirtException { 67 LongByReference libVer = new LongByReference(); 68 processError(libvirt.virGetVersion(libVer, null, null)); 69 return libVer.getValue(); 70 } 71 72 /** 73 * Free memory pointed to by ptr. 74 */ free(final Pointer ptr)75 static void free(final Pointer ptr) { 76 Native.free(Pointer.nativeValue(ptr)); 77 Pointer.nativeValue(ptr, 0L); 78 } 79 80 /** 81 * Convert the given array of UTF-8 encoded C-Strings to an array 82 * of Strings. 83 * 84 * \note The memory used by the elements of the original array 85 * is freed. 86 */ toStringArray(final CString[] cstrarr, final int size)87 static String[] toStringArray(final CString[] cstrarr, final int size) { 88 int i = 0; 89 try { 90 final String[] result = new String[size]; 91 for (; i < size; ++i) { 92 result[i] = cstrarr[i].toString(); 93 } 94 return result; 95 } catch (RuntimeException e) { 96 for (; i < size; ++i) { 97 if (cstrarr[i] != null) { 98 cstrarr[i].free(); 99 } 100 } 101 throw e; 102 } 103 } 104 105 /** 106 * Initialize the event loop. 107 * 108 * Registers a default event loop implementation based on the 109 * poll() system call. 110 * <p> 111 * Once registered, the application has to invoke 112 * {@link #processEvent} in a loop or call {@link #runEventLoop} 113 * in another thread. 114 * <p> 115 * Note: You must call this function <em>before</em> connecting to 116 * the hypervisor. 117 * 118 * @throws LibvirtException on failure 119 * 120 * @see #processEvent 121 * @see #runLoop 122 */ initEventLoop()123 public static void initEventLoop() throws LibvirtException { 124 if (timerID.get() == -1) { 125 processError(libvirt.virEventRegisterDefaultImpl()); 126 127 // add a disabled timer which is used later to break out 128 // of the event loop 129 int id = processError(libvirt.virEventAddTimeout(-1, timer, null, null)); 130 131 // remove this timer when there already is another one 132 if (!timerID.compareAndSet(-1, id)) { 133 libvirt.virEventRemoveTimeout(id); 134 } 135 } 136 } 137 138 /** 139 * Run one iteration of the event loop. 140 * <p> 141 * Applications will generally want to have a thread which invokes 142 * this method in an infinite loop: 143 * <pre> 144 * {@code while (true) connection.processEvent(); } 145 * </pre> 146 * <p> 147 * Failure to do so may result in connections being closed 148 * unexpectedly as a result of keepalive timeout. 149 * 150 * @throws LibvirtException on failure 151 * 152 * @see #initEventLoop() 153 */ processEvent()154 public static void processEvent() throws LibvirtException { 155 processError(libvirt.virEventRunDefaultImpl()); 156 } 157 158 /** 159 * Runs the event loop. 160 * 161 * This method blocks until {@link #stopEventLoop} is called or an 162 * exception is thrown. 163 * <p> 164 * Usually, this method is run in another thread. 165 * 166 * @throws LibvirtException if there was an error during the call of a 167 * native libvirt function 168 * @throws InterruptedException if this thread was interrupted by a call to 169 * {@link java.lang.Thread#interrupt() Thread.interrupt()} 170 */ runEventLoop()171 public static void runEventLoop() throws LibvirtException, InterruptedException { 172 runLoop.set(true); 173 do { 174 processEvent(); 175 if (Thread.interrupted()) { 176 throw new InterruptedException(); 177 } 178 } while (runLoop.get()); 179 } 180 181 /** 182 * Stops the event loop. 183 * 184 * This methods stops an event loop when an event loop is 185 * currently running, otherwise it does nothing. 186 * 187 * @see #runEventLoop 188 */ stopEventLoop()189 public static void stopEventLoop() throws LibvirtException { 190 if (runLoop.getAndSet(false)) { 191 // fire the timer immediately 192 int timer = timerID.get(); 193 if (timer >= 0) { 194 libvirt.virEventUpdateTimeout(timer, 0); 195 } 196 } 197 } 198 199 /** 200 * Look up a constant of an enum by its ordinal number. 201 * 202 * @return the corresponding enum constant when such a constant exists, 203 * otherwise the element which has the biggest ordinal number 204 * assigned. 205 * 206 * @throws IllegalArgumentException if {@code ordinal} is negative 207 */ getConstant(final Class<T> c, final int ordinal)208 static <T extends Enum<T>> T getConstant(final Class<T> c, final int ordinal) { 209 if (ordinal < 0) { 210 throw new IllegalArgumentException("ordinal must be >= 0"); 211 } 212 213 T[] a = c.getEnumConstants(); 214 215 assert a.length > 0 : "there must be at least one enum constant"; 216 217 return a[Math.min(ordinal, a.length - 1)]; 218 } 219 } 220