/MDCDiscovery/src/main/java/org/smpte/_2071/_2012/mdcd/naming/dnsjava/NamingServiceImpl.java

https://bitbucket.org/psymes/34cs-st2071 · Java · 755 lines · 666 code · 77 blank · 12 comment · 119 complexity · f5f3432cb59ebbf2020e044f6e3adfe4 MD5 · raw file

  1. package org.smpte._2071._2012.mdcd.naming.dnsjava;
  2. import java.io.IOException;
  3. import java.net.InetAddress;
  4. import java.net.InetSocketAddress;
  5. import java.net.UnknownHostException;
  6. import java.util.ArrayList;
  7. import java.util.Arrays;
  8. import java.util.Collections;
  9. import java.util.Comparator;
  10. import java.util.HashMap;
  11. import java.util.HashSet;
  12. import java.util.LinkedHashSet;
  13. import java.util.List;
  14. import java.util.Map;
  15. import java.util.Queue;
  16. import java.util.Set;
  17. import java.util.Stack;
  18. import java.util.concurrent.ConcurrentLinkedQueue;
  19. import java.util.logging.Level;
  20. import javax.naming.NamingException;
  21. import org.smpte._2071._2012.mdcd.ServiceInstance;
  22. import org.smpte._2071._2012.mdcd.ServiceName;
  23. import org.smpte._2071._2012.mdcd.impl.Utils;
  24. import org.smpte._2071._2012.mdcd.naming.AbstractNamingServiceImpl;
  25. import org.smpte._2071._2012.mdcd.naming.CompoundKeyMap;
  26. import org.smpte._2071._2012.mdcd.naming.NameRecord;
  27. import org.smpte._2071._2012.mdcd.net.InetAddressUtils;
  28. import org.xbill.DNS.AAAARecord;
  29. import org.xbill.DNS.ARecord;
  30. import org.xbill.DNS.CNAMERecord;
  31. import org.xbill.DNS.DClass;
  32. import org.xbill.DNS.ExtendedResolver;
  33. import org.xbill.DNS.Lookup;
  34. import org.xbill.DNS.MXRecord;
  35. import org.xbill.DNS.Message;
  36. import org.xbill.DNS.NAPTRRecord;
  37. import org.xbill.DNS.NSRecord;
  38. import org.xbill.DNS.Name;
  39. import org.xbill.DNS.PTRRecord;
  40. import org.xbill.DNS.Record;
  41. import org.xbill.DNS.Resolver;
  42. import org.xbill.DNS.SOARecord;
  43. import org.xbill.DNS.SRVRecord;
  44. import org.xbill.DNS.Section;
  45. import org.xbill.DNS.SimpleResolver;
  46. import org.xbill.DNS.TXTRecord;
  47. import org.xbill.DNS.TextParseException;
  48. import org.xbill.DNS.Type;
  49. public class NamingServiceImpl extends AbstractNamingServiceImpl
  50. {
  51. private static final Comparator<? super Record> DNSComparator = new Comparator<Record>()
  52. {
  53. @Override
  54. public int compare(Record o1, Record o2)
  55. {
  56. if (o1 == o2 || o1.equals(o2))
  57. {
  58. return 0;
  59. }
  60. int n = o1.getType() - o2.getType();
  61. if (n != 0)
  62. {
  63. return n;
  64. }
  65. n = o1.getDClass() - o2.getDClass();
  66. if (n != 0)
  67. {
  68. return n;
  69. }
  70. n = o1.getName().compareTo(o2.getName());
  71. if (n != 0)
  72. {
  73. return n;
  74. }
  75. return 0;
  76. }
  77. };
  78. private static final long ERROR_THRESHOLD = 60000;
  79. private ExtendedResolver defaultResolver = null;
  80. private Queue<SimpleResolver> specifiedResolvers = null;
  81. private Map<Resolver, Long> resolverErrors = new HashMap<Resolver, Long>();
  82. public NamingServiceImpl()
  83. throws NamingException
  84. {
  85. super();
  86. try
  87. {
  88. defaultResolver = new ExtendedResolver();
  89. } catch (Exception e)
  90. {
  91. Utils.log(log, Level.WARNING, "Could not create default resolver " + (e.getMessage() != null ? " - " + e.getMessage() : "."), Level.FINE, e);
  92. }
  93. }
  94. @Override
  95. public void setLocalAddress(final InetAddress localAddress)
  96. throws NamingException
  97. {
  98. super.setLocalAddress(localAddress);
  99. if (specifiedResolvers != null)
  100. {
  101. for (SimpleResolver resolver : specifiedResolvers)
  102. {
  103. resolver.setLocalAddress(localAddress);
  104. }
  105. } else
  106. {
  107. Stack<Resolver> stack = new Stack<Resolver>();
  108. stack.addAll(Arrays.asList(defaultResolver.getResolvers()));
  109. while (!stack.isEmpty())
  110. {
  111. Resolver resolver = stack.pop();
  112. if (resolver instanceof SimpleResolver)
  113. {
  114. ((SimpleResolver) resolver).setLocalAddress(localAddress);
  115. } else if (resolver instanceof ExtendedResolver)
  116. {
  117. stack.addAll(Arrays.asList(((ExtendedResolver) resolver).getResolvers()));
  118. }
  119. }
  120. }
  121. }
  122. @Override
  123. public void setServerAddresses(Set<InetSocketAddress> serverAddresses)
  124. throws NamingException
  125. {
  126. if (this.specifiedResolvers != null)
  127. {
  128. this.specifiedResolvers.clear();
  129. }
  130. if (serverAddresses != null)
  131. {
  132. this.serverAddresses.clear();
  133. }
  134. addServerAddresses(serverAddresses);
  135. }
  136. @Override
  137. public boolean addServerAddresses(Set<InetSocketAddress> serverAddresses)
  138. throws NamingException
  139. {
  140. if (this.specifiedResolvers == null)
  141. {
  142. this.specifiedResolvers = new ConcurrentLinkedQueue<SimpleResolver>();
  143. }
  144. if (serverAddresses == null)
  145. {
  146. this.serverAddresses = new LinkedHashSet<InetSocketAddress>();
  147. }
  148. HashSet<InetSocketAddress> newServerAddresses = new HashSet<InetSocketAddress>();
  149. for (InetSocketAddress serverAddress : serverAddresses)
  150. {
  151. if (!this.serverAddresses.contains(serverAddress))
  152. {
  153. try
  154. {
  155. SimpleResolver newResolver = new SimpleResolver(serverAddress.getAddress().getHostAddress());
  156. newResolver.setAddress(serverAddress);
  157. newResolver.setLocalAddress(localAddress);
  158. Lookup lookup = new Lookup("@", Type.SOA);
  159. lookup.setResolver(newResolver);
  160. lookup.run();
  161. if (lookup.getResult() == Lookup.SUCCESSFUL)
  162. {
  163. this.specifiedResolvers.add(newResolver);
  164. newServerAddresses.add(serverAddress);
  165. } else
  166. {
  167. log.warning("Could not connect to Naming Service \"" + this + " at server address \"" + serverAddress + "\", address not added.");
  168. }
  169. } catch (TextParseException e)
  170. {
  171. NamingException ne = new NamingException(e.getMessage());
  172. ne.setStackTrace(e.getStackTrace());
  173. throw ne;
  174. } catch (UnknownHostException e)
  175. {
  176. NamingException ne = new NamingException(e.getMessage());
  177. ne.setStackTrace(e.getStackTrace());
  178. throw ne;
  179. }
  180. }
  181. }
  182. if (newServerAddresses.size() > 0)
  183. {
  184. return super.addServerAddresses(newServerAddresses);
  185. } else
  186. {
  187. return false;
  188. }
  189. }
  190. @Override
  191. public List<NameRecord> reverseQuery(InetAddress address)
  192. throws NamingException
  193. {
  194. List<NameRecord> results = new ArrayList<NameRecord>();
  195. List<ResourceRecord> records = new ArrayList<ResourceRecord>();
  196. List<ResourceRecord> tempRecords;
  197. int[] queryTypes = new int[] {Type.PTR};
  198. for (int type : queryTypes)
  199. {
  200. tempRecords = listRecords(new ServiceName(InetAddressUtils.reverseMapAddress(address)), type);
  201. if (tempRecords != null && tempRecords.size() > 0)
  202. {
  203. records.addAll(tempRecords);
  204. }
  205. }
  206. if (records.size() > 0)
  207. {
  208. for (ResourceRecord record : records)
  209. {
  210. Name host = record.getHost();
  211. Name target = record.getTarget();
  212. Name value = host != null ? host : target;
  213. results.add(new NameRecord(value.toString(), address));
  214. }
  215. }
  216. return results;
  217. }
  218. @Override
  219. public List<NameRecord> query(ServiceName serviceName)
  220. throws NamingException
  221. {
  222. List<NameRecord> results = new ArrayList<NameRecord>();
  223. List<ResourceRecord> records = new ArrayList<ResourceRecord>();
  224. List<ResourceRecord> tempRecords;
  225. int[] queryTypes = new int[] {Type.A, Type.PTR, Type.SRV};
  226. for (int type : queryTypes)
  227. {
  228. tempRecords = listRecords(serviceName, type);
  229. if (tempRecords != null && tempRecords.size() > 0)
  230. {
  231. records.addAll(tempRecords);
  232. }
  233. }
  234. if (records.size() > 0)
  235. {
  236. for (ResourceRecord record : records)
  237. {
  238. Name host = record.getHost();
  239. Name target = record.getTarget();
  240. Name value = host != null ? host : target;
  241. results.add(new NameRecord(value.toString(), record.getAddresses()));
  242. }
  243. }
  244. return results;
  245. }
  246. @Override
  247. public List<ServiceInstance> serviceDiscovery(ServiceName serviceName)
  248. throws NamingException
  249. {
  250. ArrayList<ServiceInstance> services = new ArrayList<ServiceInstance>();
  251. List<ResourceRecord> records = new ArrayList<ResourceRecord>();
  252. List<ResourceRecord> tempRecords;
  253. int[] queryTypes = new int[] {Type.PTR, Type.SRV, Type.TXT};
  254. for (int type : queryTypes)
  255. {
  256. tempRecords = listRecords(serviceName, type);
  257. if (tempRecords != null && tempRecords.size() > 0)
  258. {
  259. records.addAll(tempRecords);
  260. }
  261. }
  262. if (records != null && records.size() > 0)
  263. {
  264. CompoundKeyMap<Name, Integer, ResourceRecord> cache = new CompoundKeyMap<Name, Integer, ResourceRecord>();
  265. Collections.sort(records, new Comparator<ResourceRecord>()
  266. {
  267. @Override
  268. public int compare(ResourceRecord nr1, ResourceRecord nr2)
  269. {
  270. int value = nr1.getName().compareTo(nr2.getName());
  271. if (value == 0)
  272. {
  273. int type1 = nr1.getType();
  274. int type2 = nr2.getType();
  275. if (type1 == type2)
  276. {
  277. return 0;
  278. }
  279. switch (type1)
  280. {
  281. case Type.SRV :
  282. return -1;
  283. case Type.TXT :
  284. return (type2 == Type.A || type2 == Type.CNAME ? -1 : 1);
  285. case Type.CNAME :
  286. return (type2 == Type.A ? -1 : 1);
  287. case Type.A :
  288. return 1;
  289. default :
  290. if (type2 == Type.SRV)
  291. {
  292. return 1;
  293. } else
  294. {
  295. return (type1 < type2 ? -1 : (type1 > type2 ? 1 : 0));
  296. }
  297. }
  298. }
  299. return value;
  300. }
  301. });
  302. // Cache Complete List of results, but service target and type.
  303. for (ResourceRecord record : records)
  304. {
  305. int type = record.getType();
  306. Name target = record.getTarget();
  307. String targetStr = target != null ? target.toString() : null;
  308. cache.put(target, record.getType(), record);
  309. if (type == Type.PTR)
  310. {
  311. if (target != null)
  312. {
  313. services.addAll(serviceDiscovery(new ServiceName(targetStr, null)));
  314. }
  315. } else if (type == Type.SRV)
  316. {
  317. ServiceInstance service = new ServiceInstance(serviceName);
  318. services.add(service);
  319. Name host = record.getHost();
  320. service.setHost(host != null ? host.toString() : null);
  321. service.setPort(record.getPort());
  322. service.setPriority(record.getPriority());
  323. service.setTarget(targetStr);
  324. service.setWeight(record.getWeight());
  325. if (targetStr != null)
  326. {
  327. List<InetAddress> serviceAddresses = listAddresses(targetStr);
  328. if (serviceAddresses != null)
  329. {
  330. service.setAddresses(serviceAddresses);
  331. }
  332. }
  333. } else if (type == Type.TXT)
  334. {
  335. if (services.size() > 0)
  336. {
  337. ServiceInstance service = services.get(services.size() - 1);
  338. if (record.getTextRecords() != null)
  339. {
  340. service.addTextRecords(record.getTextRecords());
  341. } else
  342. {
  343. Exception e = new Exception("We Recieved a TXT record with no Text! This should not have happened!");
  344. Utils.log(log, Level.WARNING, e.getMessage(), Level.FINE, e);
  345. }
  346. }
  347. }
  348. }
  349. }
  350. return services;
  351. }
  352. private List<ResourceRecord> listRecords(ServiceName serviceName, int type)
  353. throws NamingException
  354. {
  355. List<ResourceRecord> records = new ArrayList<ResourceRecord>();
  356. List<String> domains = new ArrayList<String>();
  357. final String domain = serviceName.getDomain();
  358. if (domain == null || domain.length() == 0)
  359. {
  360. synchronized (this.domains)
  361. {
  362. domains.addAll(this.domains);
  363. }
  364. } else
  365. {
  366. domains.add(domain);
  367. }
  368. if (this.specifiedResolvers != null)
  369. {
  370. for (String tempDomain : domains)
  371. {
  372. for (SimpleResolver resolver : this.specifiedResolvers)
  373. {
  374. try
  375. {
  376. Long lastError = resolverErrors.get(resolver);
  377. if (lastError == null || lastError + ERROR_THRESHOLD < System.currentTimeMillis())
  378. {
  379. records.addAll(lookup(resolver, type, serviceName.getNameWithoutDomain(), tempDomain));
  380. }
  381. } catch (NamingException e)
  382. {
  383. Utils.log(log, Level.WARNING, "Error querying \"" + serviceName.getNameWithoutDomain() + "." + tempDomain + "\" of type \"" + typeToString(type) + "\"" + (e.getMessage() != null ? " - " + e.getMessage() : "."), Level.FINE, e);
  384. } catch (IOException e)
  385. {
  386. resolverErrors.put(resolver, System.currentTimeMillis());
  387. Utils.log(log, Level.WARNING, "Error querying \"" + serviceName.getNameWithoutDomain() + "." + tempDomain + "\" of type \"" + typeToString(type) + "\"" + (e.getMessage() != null ? " - " + e.getMessage() : "."), Level.FINE, e);
  388. }
  389. }
  390. }
  391. } else
  392. {
  393. for (String tempDomain : domains)
  394. {
  395. try
  396. {
  397. records.addAll(lookup(this.defaultResolver, type, serviceName.getNameWithoutDomain(), tempDomain));
  398. } catch (NamingException e)
  399. {
  400. Utils.log(log, Level.WARNING, "Error querying \"" + serviceName.getNameWithoutDomain() + "." + tempDomain + "\" of type \"" + typeToString(type) + "\"" + (e.getMessage() != null ? " - " + e.getMessage() : "."), Level.FINE, e);
  401. } catch (IOException e)
  402. {
  403. Utils.log(log, Level.WARNING, "Error querying \"" + serviceName.getNameWithoutDomain() + "." + tempDomain + "\" of type \"" + typeToString(type) + "\"" + (e.getMessage() != null ? " - " + e.getMessage() : "."), Level.FINE, e);
  404. }
  405. }
  406. }
  407. return records;
  408. }
  409. public List<InetAddress> listAddresses(String name)
  410. throws NamingException
  411. {
  412. List<InetAddress> addresses = new ArrayList<InetAddress>();
  413. List<ResourceRecord> records = new ArrayList<ResourceRecord>();
  414. List<ResourceRecord> tempRecords;
  415. int[] queryTypes = new int[] {Type.A, Type.AAAA, Type.CNAME, Type.PTR, Type.SRV};
  416. for (int type : queryTypes)
  417. {
  418. tempRecords = listRecords(new ServiceName(name), type);
  419. if (tempRecords != null && tempRecords.size() > 0)
  420. {
  421. records.addAll(tempRecords);
  422. }
  423. }
  424. if (records != null)
  425. {
  426. for (ResourceRecord record : records)
  427. {
  428. Name target = record.getTarget();
  429. switch (record.getType())
  430. {
  431. case Type.A :
  432. case Type.AAAA :
  433. addresses.addAll(record.getAddresses());
  434. break;
  435. case Type.CNAME :
  436. case Type.PTR :
  437. case Type.SRV :
  438. try
  439. {
  440. if (target != null)
  441. {
  442. addresses.addAll(listAddresses(target.toString()));
  443. }
  444. } catch (Exception e)
  445. {
  446. Utils.log(log, Level.WARNING, "Error resolving addresses for \"" + name + "\"" + (e.getMessage() != null ? " - " + e.getMessage() : "."), Level.FINE, e);
  447. }
  448. break;
  449. }
  450. }
  451. }
  452. return addresses;
  453. }
  454. /**
  455. * Lookup Naming Records from the resolver.
  456. *
  457. * @param resolver the DNS Resolver.
  458. * @param name The host name
  459. * @param domain The domain name. If null, name is expected to be fully qualified.
  460. * @return
  461. * @throws NamingException
  462. * @throws IOException
  463. */
  464. @SuppressWarnings("unchecked")
  465. private List<ResourceRecord> lookup(Resolver resolver, int type, String name, String domain)
  466. throws NamingException, IOException
  467. {
  468. List<ResourceRecord> records = new ArrayList<ResourceRecord>();
  469. Name domainName;
  470. Name hostName;
  471. if (domain != null)
  472. {
  473. if (!domain.endsWith("."))
  474. {
  475. domain += ".";
  476. }
  477. domainName = new Name(domain);
  478. hostName = new Name(name, domainName);
  479. } else
  480. {
  481. if (!name.endsWith("."))
  482. {
  483. name += ".";
  484. }
  485. domainName = null;
  486. hostName = new Name(name);
  487. }
  488. Message query = Message.newQuery(Record.newRecord(hostName, type, DClass.IN));
  489. Message response = null;
  490. boolean errorOccurred = false;
  491. byte retry = 1;
  492. do
  493. {
  494. try
  495. {
  496. response = resolver.send(query);
  497. errorOccurred = false;
  498. break;
  499. } catch (IOException e)
  500. {
  501. errorOccurred = true;
  502. try
  503. {
  504. Thread.sleep(500);
  505. } catch (InterruptedException ie)
  506. {
  507. // ignore
  508. }
  509. if (retry++ > 3)
  510. {
  511. throw e;
  512. }
  513. }
  514. } while (errorOccurred);
  515. switch (response.getRcode())
  516. {
  517. case 1 :
  518. throw new NamingException("Error querying " + typeToString(type) + " \"" + hostName + "\" - DNS error code 1: Format Error");
  519. case 2 :
  520. throw new NamingException("Error querying " + typeToString(type) + " \"" + hostName + "\" - DNS error code 2: Server Failure");
  521. case 3 :
  522. Utils.log(log, Level.WARNING, "Issue querying " + typeToString(type) + " \"" + hostName + "\" - DNS error code 3: Name Not Found", Level.FINE, new NamingException("DNS error code 3: Name Not Found"));
  523. break;
  524. case 4 :
  525. throw new NamingException("Error querying " + typeToString(type) + " \"" + hostName + "\" - DNS error code 4: Not Implemented");
  526. case 5 :
  527. throw new NamingException("Error querying " + typeToString(type) + " \"" + hostName + "\" - DNS error code 5: Request Refused");
  528. }
  529. Record[] answers = response.getSectionArray(Section.ANSWER);
  530. Arrays.sort(answers, DNSComparator);
  531. if (answers.length > 0)
  532. {
  533. for (Record answer : answers)
  534. {
  535. ResourceRecord record = null;
  536. switch(answer.getType())
  537. {
  538. case Type.A :
  539. ARecord a = (ARecord) answer;
  540. record = new ResourceRecord(answer.getType(), answer.getName());
  541. record.setHost(answer.getName());
  542. record.addAddress(a.getAddress());
  543. records.add(record);
  544. break;
  545. case Type.AAAA :
  546. AAAARecord aaaa = (AAAARecord) answer;
  547. record = new ResourceRecord(answer.getType(), answer.getName());
  548. record.setHost(answer.getName());
  549. record.addAddress(aaaa.getAddress());
  550. records.add(record);
  551. break;
  552. case Type.CNAME :
  553. CNAMERecord cname = (CNAMERecord) answer;
  554. record = new ResourceRecord(answer.getType(), answer.getName());
  555. record.setHost(cname.getTarget());
  556. record.setTarget(cname.getTarget());
  557. break;
  558. case Type.PTR :
  559. PTRRecord ptr = (PTRRecord) answer;
  560. record = new ResourceRecord(answer.getType(), answer.getName());
  561. record.setHost(ptr.getTarget());
  562. record.setTarget(ptr.getTarget());
  563. records.add(record);
  564. break;
  565. case Type.SRV :
  566. SRVRecord srv = (SRVRecord) answer;
  567. record = new ResourceRecord(answer.getType(), answer.getName());
  568. record.setHost(srv.getTarget());
  569. record.setPort(srv.getPort());
  570. record.setPriority(srv.getPriority());
  571. record.setWeight(srv.getWeight());
  572. record.setTarget(srv.getTarget());
  573. records.add(record);
  574. break;
  575. case Type.TXT :
  576. TXTRecord txt = (TXTRecord) answer;
  577. record = new ResourceRecord(answer.getType(), answer.getName());
  578. record.setHost(null);
  579. record.addTextRecords(txt.getStrings());
  580. records.add(record);
  581. break;
  582. case Type.NAPTR :
  583. NAPTRRecord naptr = (NAPTRRecord) answer;
  584. record = new ResourceRecord(answer.getType(), answer.getName());
  585. record.setFlags(naptr.getFlags());
  586. record.setOrder(naptr.getOrder());
  587. record.setPreference(naptr.getPreference());
  588. record.setRegexp(naptr.getRegexp());
  589. record.setReplacement(naptr.getReplacement());
  590. record.setService(naptr.getService());
  591. records.add(record);
  592. break;
  593. case Type.NS :
  594. NSRecord ns = (NSRecord) answer;
  595. record = new ResourceRecord(answer.getType(), answer.getName());
  596. record.setHost(ns.getTarget());
  597. record.setTarget(ns.getTarget());
  598. records.add(record);
  599. break;
  600. case Type.MX :
  601. MXRecord mx = (MXRecord) answer;
  602. record = new ResourceRecord(answer.getType(), answer.getName());
  603. record.setPriority(mx.getPriority());
  604. record.setHost(mx.getTarget());
  605. record.setTarget(mx.getTarget());
  606. records.add(record);
  607. break;
  608. case Type.SOA :
  609. SOARecord soa = (SOARecord) answer;
  610. record = new ResourceRecord(answer.getType(), answer.getName());
  611. record.setHost(soa.getHost());
  612. record.setTarget(soa.getName());
  613. records.add(record);
  614. break;
  615. }
  616. }
  617. }
  618. return records;
  619. }
  620. private String typeToString(int type)
  621. {
  622. switch (type)
  623. {
  624. case Type.A :
  625. return "A";
  626. case Type.A6 :
  627. return "A6";
  628. case Type.AAAA :
  629. return "AAAA";
  630. case Type.ANY :
  631. return "ANY";
  632. case Type.AXFR :
  633. return "AXFR";
  634. case Type.CERT :
  635. return "CERT";
  636. case Type.CNAME :
  637. return "CNAME";
  638. case Type.DHCID :
  639. return "DHCID";
  640. case Type.DNAME :
  641. return "DNAME";
  642. case Type.DNSKEY :
  643. return "DNSKEY";
  644. case Type.DS :
  645. return "DS";
  646. case Type.EID :
  647. return "EID";
  648. case Type.IPSECKEY :
  649. return "IPSECKEY";
  650. case Type.IXFR :
  651. return "IXFR";
  652. case Type.KEY :
  653. return "KEY";
  654. case Type.MX :
  655. return "MX";
  656. case Type.NAPTR :
  657. return "NAPTR";
  658. case Type.NS :
  659. return "NS";
  660. case Type.PTR :
  661. return "PTR";
  662. case Type.SOA :
  663. return "SOA";
  664. case Type.SIG :
  665. return "SIG";
  666. case Type.TKEY :
  667. return "TKEY";
  668. case Type.TSIG :
  669. return "TSIG";
  670. case Type.TXT :
  671. return "TXT";
  672. case Type.SRV :
  673. return "SRV";
  674. default :
  675. return Integer.toBinaryString(type);
  676. }
  677. }
  678. }