Как заставить uCanAccess использовать аутентификацию Samba со специальными символами в имени пользователя или пароле? - PullRequest
0 голосов
/ 13 сентября 2018

TL; DR: Какую Database.FileFormat константу следует использовать для базы данных MS Access 2000-2003 при создании объекта базы данных?

Я создал тестовое приложение SAMBA, используя JCIFS .Это позволяет мне создавать / перезаписывать файлы, если указаны правильные учетные данные для аутентификации, независимо от того, на каком ПК в домене я его использую.

У меня также есть приложение, которое использует uCanAccess / jackcess для подключения к MDB насетевой ресурс.Однако (из того, что я понимаю), он использует учетные данные вошедшего в систему пользователя, некоторые из которых имеют доступ только для чтения.Только системные / сетевые администраторы имеют право на запись.

База данных не защищена паролем.(Мне не нужно вводить пароль при его открытии.)

Мое намерение состоит в том, чтобы приложение запрашивало учетные данные администратора Samba перед записью в БД, используя их в соединении uCanAccess, чтобыон не выдает java.nio.channels.NonWritableChannelException, как показано ниже:

java.nio.channels.NonWritableChannelException
  at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:747)
  at com.healthmarketscience.jackcess.impl.PageChannel.writePage(PageChannel.java:310)
  at com.healthmarketscience.jackcess.impl.PageChannel.writePage(PageChannel.java:247)
  at com.healthmarketscience.jackcess.impl.TableImpl.writeDataPage(TableImpl.java:1980)
  at com.healthmarketscience.jackcess.impl.TableImpl.addRows(TableImpl.java:2229)
  at com.healthmarketscience.jackcess.impl.TableImpl.addRow(TableImpl.java:2067)
  at net.ucanaccess.converters.UcanaccessTable.addRow(UcanaccessTable.java:44)
  at net.ucanaccess.commands.InsertCommand.insertRow(InsertCommand.java:101)
  at net.ucanaccess.commands.InsertCommand.persist(InsertCommand.java:148)
  at net.ucanaccess.jdbc.UcanaccessConnection.flushIO(UcanaccessConnection.java:315)
  at net.ucanaccess.jdbc.UcanaccessConnection.commit(UcanaccessConnection.java:205)
  at net.ucanaccess.jdbc.AbstractExecute.executeBase(AbstractExecute.java:217)
  at net.ucanaccess.jdbc.Execute.execute(Execute.java:46)
  at net.ucanaccess.jdbc.UcanaccessPreparedStatement.execute(UcanaccessPreparedStatement.java:228)
  at myapp.db.Digger.addTransaction(Digger.java:993)
  at myapp.tasks.TransactionRunnable.run(TransactionRunnable.java:42)
  at java.lang.Thread.run(Thread.java:745)

Обновление: Я пытался использовать класс smbFileChannel Гордом Томпсоном и Дж.Т. Алхборном, показано здесь .Мой код, основанный на основном классе, показанном в этом ответе, выглядит следующим образом:

// Ask the user for login credentials and the path to the database
String smbURL = (chosenDir.endsWith("/") ? chosenDir : chosenDir + '/') 
  + dbName;
System.out.println("DB Path to use for URL: " + smbURL);
URL u = new URL(smbURL);
try (
  // construct the SMB DB URL
  SmbFileChannel sfc = new SmbFileChannel(smbURL);
  Database db = new DatabaseBuilder().setChannel(sfc)
    .setFileFormat(Database.FileFormat.GENERIC_JET4).create();
) {
  // Model the table
  Table tbl = new TableBuilder("Transactions")
    .addColumn(new ColumnBuilder("TransactionID", DataType.LONG).setAutoNumber(true))
    .addColumn(new ColumnBuilder("ControllerID", DataType.LONG).setAutoNumber(false))
    .addColumn(new ColumnBuilder("ReaderID", DataType.LONG).setAutoNumber(false))
    .addColumn(new ColumnBuilder("Event", DataType.LONG).setAutoNumber(false))
    .addColumn(new ColumnBuilder("Timestamp", DataType.SHORT_DATE_TIME).setAutoNumber(false))
    .addColumn(new ColumnBuilder("Number", DataType.LONG).setAutoNumber(false))
    .addIndex(new IndexBuilder(IndexBuilder.PRIMARY_KEY_NAME).addColumns("TransactionID").setPrimaryKey())
    .toTable(db);
  // Add the row
  Map<String, Object> values = new HashMap<>();
  values.put("ControllerID", cid);
  values.put("ReaderID", rid);
  values.put("Event", evtNum);
  values.put("Timestamp", ts); // Long; must be converted to DataType.SHORT_DATE_TIME
  values.put("Number", accNum);
  tbl.addRowFromMap(values);
} catch (IOException IOEx) {
  System.err.println(
    "Failed to write record to Transactions table in database: " 
    + IOEx.getMessage()
   );
   IOEx.printStackTrace(System.err);
  } catch (Exception ex) {
    System.err.println(
      '[' + ex.getClass().getSimpleName() + "]: Failed to write record to "
      + "Transactions table in database: " + ex.getMessage()
    );
    ex.printStackTrace(System.err);
  }

Выполнение приведенного выше кода приводит к следующему выводу:

DB Path to use for URL: smb://machine.vpnName/Storage/me/dbs/DBName.mdb
Failed to write record to Transactions table in database: Logon failure: account currently disabled.
jcifs.smb.SmbAuthException: Logon failure: account currently disabled.
   at jcifs.smb.SmbTransport.checkStatus(SmbTransport.java:546)
    at jcifs.smb.SmbTransport.send(SmbTransport.java:663)
    at jcifs.smb.SmbSession.sessionSetup(SmbSession.java:390)
    at jcifs.smb.SmbSession.send(SmbSession.java:218)
    at jcifs.smb.SmbTree.treeConnect(SmbTree.java:176)
    at jcifs.smb.SmbFile.doConnect(SmbFile.java:911)
    at jcifs.smb.SmbFile.connect(SmbFile.java:957)
    at jcifs.smb.SmbFile.connect0(SmbFile.java:880)
    at jcifs.smb.SmbFile.open0(SmbFile.java:975)
    at jcifs.smb.SmbFile.open(SmbFile.java:1009)
    at jcifs.smb.SmbRandomAccessFile.<init>(SmbRandomAccessFile.java:57)
    at jcifs.smb.SmbRandomAccessFile.<init>(SmbRandomAccessFile.java:42)
    at samba.SmbFileChannel.<init>(SmbFileChannel.java:30)
    at samba.SambaLanWriteTest.writeTest(SambaLanWriteTest.java:130)
    at samba.SambaLanWriteTest.main(SambaLanWriteTest.java:181)

У меня есть доступ на запись ктестовая копия файла базы данных при использовании Windows File Explorer.Я выбираю его, когда будет предложено.

Обновление 2: Я понял, что не добавил имя пользователя и пароль к URL-адресу smb://, как показывает пример Томпсона.Я изменил код так:

String smbCred = "smb://" + auth.getUsername() + ":" + auth.getPassword() + "@",
  fixer = chosenDir.replace("\\", "/").replace("smb://", smbCred),
  smbURL = fixer + dbName;
System.out.println("DB Path to use for URL: " + smbURL);
// URL u = new URL(smbURL);

Следующая проблема, с которой я столкнулся, состояла в том, что мой пароль содержит специальных недопустимых символов (таких как '@', ':', ';','=' и '?').Я избежал их с помощью java.net.URLEncoder.encode() на auth.getUsername() и auth.getPassword(), поэтому код не выдает MalformedURLException при создании SmbChannel.Однако следующее исключение, с которым я столкнулся, выглядит следующим образом:

Failed to write record to Transactions table in database: File format GENERIC_JET4 [VERSION_4] does not support file creation for null
java.io.IOException: File format GENERIC_JET4 [VERSION_4] does not support file creation for null
    at com.healthmarketscience.jackcess.impl.DatabaseImpl.create(DatabaseImpl.java:444)

Какую константу Database.FileFormat следует использовать для базы данных MS Access 2000-2003 при создании объекта Database?

1 Ответ

0 голосов
/ 14 сентября 2018

Оказывается, мне нужно было использовать Database.FileFormat.V2000.

После этого все было гладко (хотя мне все еще нужно разобраться, как заставить метку Long конвертировать правильно).

...