Es können Fehler beim installieren von Magento Themes entstehen. Wenn man z.B. nach der Installationsanleitung eine dump.sql einspielen will, kann es sein das bei einem MySql 5.1 Server ein Fehler im BTREE Error auftaucht.
ERROR 1064 (42000) at line 1561: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘USING BTREE, …
Eine einfache Lösung bietet hier wieder ein kleines Command in der Konsole.
sed -i -r 's/\(([^)]+)\) USING BTREE/USING BTREE (\1)/g' mydump.sql
Für alle die häufiger E-Mail Verläufe oder auch andere Textfiles Archivieren und Migrieren wollen für eine bessere Bestandsaufnahme oder einfach um es sauber ablegen zu können habe ich eine Möglichkeit gefunden mit Open Source Tools eine Migration von Textfiles in PDF’s vorzunehmen. Und das ganze in der Konsole.
Es ist zwar nicht alltäglich eine solche Aufgabenstellung aber man findet relativ wenig dazu im Netz, daher hat es jetzt ein paar Nächte gedauert bis wir einen guten Weg gefunden haben.
Zum einen nutzen wir, egal ob auf Windows oder Unix Systemen.
enscript
Ghostscript
Enscript erstellt uns aus einfachen Textdateien schöne PS Files um diese anschließend weiter zu verarbeiten.
Wie man enscript unter Windows zum laufen bekommt findet ihr hier. Es ist ein graus mit enscript. Aber sobald es läuft funktioniert es ohne Probleme.
Nachdem beide Programme zu unserer Zufriedenheit laufen, könnt ihr mit zwei einfachen Befehlen die PDF erzeugen.
Hi alle zusammen. Ich habe mich mal wieder etwas im Gewusel und Getümmel der Programmierung verloren. Dabei ist mir aufgefallen, das alle Parser die einen MT940 verarbeiten wollen Fehler haben und teilweise nicht funktionieren. Dem ganzen bin ich mal auf den Leib gerückt und präsentier euch hier einen freien MT940 Parser. Könnt ihr kostenlos hier downloaden.
Für alle die nicht wissen was der MT940 macht:
MT940 (MT=Message Type) ist der SWIFT-Standard (Banking Communication Standard) zur elektronischen Übermittlung von Kontoauszug-Daten. Bei verschiedenen Online-Banking-Programmen wird MT940 als Schnittstelle verwendet zu anderen Programmen (z. B. für die Buchhaltung), mit denen die Kontoauszug-Daten weiter verarbeitet werden.
Unterstütz werden alle nötigen Tag’s:
:21: Bezugsreferenznummer
:25: M Kontobezeichnung
:28C: M Auszugsnummer
:60a: M Anfangssaldo
:61: Umsatz
:86: Mehrzweckfeld
:62a: M Schlusssaldo
:64: Aktueller Valutensaldo
:65: Zukünftige Valutensalden
:86: Mehrzweckfeld
Das ganze gibt es in einem Netbeans Projekt als ZIP file zum Download.
Update 25.10.11
Ich habe für euch das Mehrzweckfeld :86: überarbeitet. Ihr findet im Projekt eine neue Klasse die Mehrzweckfeld heißt und in der alle nötigen Felder
Verwendungszweck
Name
BLZ
Kontonummer etc.
geparsed werden. Das ganze könnt ihr euch wieder in der Main ausgeben lassen. Ebenso unterstütze ich jetzt ein Mehrzweckfeld das sich über mehr als eine Zeile erstreckt.
Ich entwickle sehr gerne mit meinem Macbook, leider habe ich feststellen müssen das die Migration von einer Konakart Installation auf einen Glassfish etwas anders läuft als in der Dokumentation beschrieben.
Folgende Befehle können verwendet werden!
make_ear
In meinem zweiten Versuch mit make_ear hat es super funktioniert. Ich würde es mir fast sogar zutrauen das ich es beim ersten mal übersehen habe. make_ear erzeugt im Ordner ear/ eine konakart.ear file. Diese einfach nur auf dem glassfish deployen und viola it runs.
Dieser Befehlt ist ziemlich sinnfrei. Er erstellt unter dem MAC einen Ordner konakart.ear und nicht die File um es dem glassfish schmackhaft zu machen.
Alternative make_wars
Um die korrekten Dateien zu erstellen, geht in den Installationsordner von konakart und in den Subordner custon also: /konakart/custom hier drin befindet sich die build.xml die Konakart benötigt um alle weiteren Befehle auszuführen.
Anschließend führt ihr folgenden Befehl in der Konsole aus: ./bin/ant make_wars Es wird einen Moment dauern aber anschließend, bei korrekter Verarbeitung werdet ihr BUILD SUCCESS am Ende erhalten.
Am einfachsten ist, ihr erstellt die .war Files und ladet alle 3 im Admin Interface auf den Server. Alle generierten Files werden im Ordner /konakart/custom/war/ abgelegt:
birtviewer.war
konakart.war
konakartadmin.war
Nachdem Ihr die .war Files im glassfish deployed habt, geht es an die Datenbank. Soweit noch keine vorhanden ist. Hierzu ladet euch auf den Server am besten per FTP die konakart_demo.sql. Diese findet ihr unter: /konakart/database/MySql/
Geht in die Konsole und legt die Datenbank an:
# > mysql -u root -p
mysql > CREATE DATABASE konakart;
mysql > quit;
anschließend noch die konakart_demo.sql in die konakart datenbank importieren.
# > mysql -u root -p konakart < ./var/tmp/konakart_demo.sql
Nachdem ihr erfolgreich die Datenbank importiert habt, müsst ihr nur noch in den Application Ordner von Konakart die properties Files anpassen:
Also zurück in den domain Ordner des glassfisher z.B.
darin findet ihr schon die Einträge für die Datenbank. Einfach die Nutzer und das Passwort noch anpassen euren Glassfish neu starten und viola das System läuft.
Arbeiten mit dem Konakart Webservice kann einige Schwierigkeiten mit sich bringen. Ich war auch erst einmal ein paar Stunden und Tage darüber die passende IDE und den richtigen Weg zu wählen. Meine Lösung:
Eclipse mit einer virtuellen Maschine auf der eine Konakartinstallation läuft.
Netbeans RPC Webservices ist leider nicht möglich da sich Netbeans dagegen sträubt und scheinbar einige Teile der WSDL falsch übersetzt. Wie ich schon in ein paar Beiträgen vorher beschrieben habe wäre es sinnvoll die Serviceverbindung und Abarbeitung aller Daten in einem Eclipse Projekt durch zu führen.
Schritt 1: Verbindung zu Konakart
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.konakartadmin.ws.KKWSAdminIf;
import com.konakartadmin.ws.KKWSAdminIfServiceLocator;
/**
* KonakartService Class
* per extend in die Subklasse z.b. Kategorie einbinden und per aufruf init()
* zum webservice verbinden
**/
public class KonakartService {
public static Log log = LogFactory.getLog(KonakartService.class);
public static KKWSAdminIf eng;
/** Default credentials for accessing the KonaKart Application Engine */
private static String DEFAULT_USERNAME = "admin@konakart.com";
private static String DEFAULT_PASSWORD = "princess";
/** The session id returned by a successful login */
public static String sessionId;
/**
* @param args
*/
public static void init() {
try {
/*
* Instantiate a KonaKart Engine instance
*/
eng = new KKWSAdminIfServiceLocator().getKKWSAdmin();
eng.setEndpoint("MEINEIP"); // set ip address or hostname
sessionId = eng.login(DEFAULT_USERNAME, DEFAULT_PASSWORD); // get session id
log.info(DEFAULT_USERNAME + " logged in successfully and got session " + sessionId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Wie schon angeschlagen im letzten Post, heute geht es um die ListView Optimierung in Android. In einem sehr interessanten Webcast von Google I/O 2010 gab es schon einiges sehr sinnvolles zu ListViews und auch wieder einiges was ich dazu gelernt habe.
Für alle die es interessiert: The World of ListView
Hier noch das Tutorial bzw. HowTo zu dem Video. Wozu ViewHandler gebraucht werden und wie man Speicherschonend die ListViews befüllt. Anschließend noch ein kleiner Ausschnitt wie man ListViews aktualisiert mit notifyDataSetChanged().
Ich gehe davon aus das jeder weiß wie man eine ListView in der Layout.xml definiert, daher fangen wir sofort an mit der implementierung der View im Code.
Der Adapter und somit das Herzstück des Tutorials. Wie definiere ich einen ViewHolder zum speichern der statischen Views für eine sinnvolle Speicherwiedernutzung.
import java.util.List;
import java.util.Random;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class ListeItemAdapter extends BaseAdapter {
private Context ctx;
private int rowResID;
private List itemList;
private LayoutInflater layoutInflater;
public String randomText = myRandomText();
private static class ViewHolder {
public static TextView text1;
public static TextView text2;
public static TextView text3;
public static ImageView status;
}
public ListeItemAdapter() { }
public ListeItemAdapter(final Context ctx, final int rowResID, final List itemList) {
this.ctx = ctx;
this.rowResID = rowResID;
this.itemList = itemList;
layoutInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return this.itemList.size();
}
public Object getItem(int position) {
return this.itemList.get(position);
}
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
public void setItemList(List itemList) {
this.itemList = itemList;
}
public View getView(int position, View v, ViewGroup vg) {
ViewHolder holder;
// prüfen ob eine view bereits existiert
if(v == null || v.getTag() == null) {
holder = new ViewHolder();
v = layoutInflater.inflate(rowResID, null); // inflate the item layout!
holder.text1 = (TextView) v.findViewById(R.id.text1);
holder.text2 = (TextView)v.findViewById(R.id.text2);
holder.text3 = (TextView)v.findViewById(R.id.text3);
holder.status = (ImageView) v.findViewById(R.id.status);
v.setTag(holder); // viewholder setzen
} else {
// laden der Views über den ViewHolder
holder = (ViewHolder) v.getTag();
}
// get item value
String item = itemList.get(position);
// Views füllen
holder.text1.setText(item);
holder.text2.setText(myRandomText());
holder.text3.setText(myRandomText());
holder.status.setImageResource(myRandomImage());
return v;
}
/**
* get random String value
* @return String
*/
public String myRandomText() {
String[] values = new String[] { "Hase","Hund","Katze","Maus","Schwein","Pferd","Esel","Kuh","Henne","Hahn","Vogel","Affe","Giraffe","Schlange" };
Random generator = new Random();
return values[generator.nextInt(values.length)];
}
/**
* get random Image Resource
* @return int
*/
private int myRandomImage() {
int[] values = new int[] { R.drawable.tick_green_00, R.drawable.tick_green_01, R.drawable.tick_green_02, R.drawable.tick_green_03 };
Random generator = new Random();
return values[generator.nextInt(values.length)];
}
}
Somit wäre eigentlich alles geklärt. Es ist fast selbst beschreibend für die, die sich schon mit ListViews auseinander gesetzt haben.
Wir werden jetzt mit einem Handler in der MainActivity noch ein delayed Handler aufrufen indem wir die Werte der Listview ändern.
Hier die veränderte Activity.
PART 2
Step1
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ListView;
public class ListActivity extends Activity {
private Context ctx;
private ListView liste;
private ListeItemAdapter adapter;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.liste);
this.ctx = this;
handler = new Handler();
Listitems = new ArrayList();
for(int i=0;i<100;i++) {
items.add(new ListeItemAdapter().randomText);
}
adapter = new ListeItemAdapter(this, R.layout.liste_item, items);
liste = (ListView) findViewById(R.id.liste);
liste.setAdapter(adapter);
Thread updateListViewThread = new Thread() {
@Override
public void run() {
super.run();
final Listitems = new ArrayList();
for(int i=0;i<100;i++) {
items.add(new ListeItemAdapter().randomText);
}
handler.postDelayed(new Runnable() {
@Override
public void run() {
adapter.setItemList(items);
adapter.notifyDataSetChanged();
}
}, 5000);
}
};
updateListViewThread.start();
}
}
Es ist ein Graus. Konakart Webshop Software arbeitet per SOAP Schnittstelle einfach nicht mit Netbeans zusammen. Die Java IDE ist sehr einfach und auch das Webservice einbinden ist mit ein paar Klicks erledigt. Ich werde euch, wenn ich noc eine andere Lösung finde darüber informieren. Aber derzeit ist es mir nicht möglich gewesen einen vernünftigen, vorallem schnellen Workaround für das Problem zu schaffen. Auch das anpassen der WSDL Files bringt keinen rechten Erfolg daher einen kurzen Tipp von mir.
Ladet euch Eclipse herunter und startet ein Java Projekt. Führt hierbei den den Webservice Client Punkt aus und includiert beide WSDL Files. Im Normalfall findet ihr sie unter:
Anschließend könnt ihr per Import in Netbeans das Projekt in euere IDE importieren. Die fehlenden JAR’s werden direkt verlinkt. Dieses könnt ihr in euer Hauptprojekt so einbinden und übernehmen. Es läuft ohne Probleme.
Es ist keine vernünftiger Workaround und eigentlich auch schade das es bisher auch noch keine vernünftige Lösung von Konakart gibt. Evtl. schaffe ich es noch die WSDL Files so anzupassen das sie auch vernünftig im Netbeans verarbeitet wird.
Die JAX-RPC Plugin Erweiterung im Netbeans macht schon einige Fortschritte.
Aber das gelbe vom Ei ist es noch nicht. Falls jemand schon andere Erfahrungen damit gemacht hat oder wie einfach es sich mit der RMI Schnittstelle arbeitet, lasst es mich bitte wissen.
Kleine Vorschau zum nächsten Blogeintrag:
Thema: Android – Listviews optimieren und mit Viewhandlern arbeiten. Recyceln von Views. Änderungen in Listviews darstellen. Das richtige Ansprechen von Feldern in Listviews. 2 verschiedene Möglichkeiten.
AIDL Prozesse oder Services sind Schnittstellen zur Kommunikation und Automatisierung außerhalb der App. Wenn deine App für Widgets oder auch für länger laufende Prozesse einiges an Ressourcen benötigt und vor allem auch nach dem schließen der Applikation weiter arbeiten soll. z.B. Streamen von Musik oder Aktualisieren von Daten bei Newsfeed’s etc. sind sogenannte Remote Services sinnvoll.
Remoteservices werden mit einer .aidl file spezifiziert, dieses beinhaltet eine Interfaceklasse die die Struktur des späteren Services erzeugt. Vieles zur Kommunikation mit dem System erzeugt Eclipse wieder von alleine, um das wir uns nicht kümmern müssen. Einmal verstanden ist es halb so schwer.
Mein Mainpackage z.B. de.jkoeber.testapp darin erstelle ich eine .aidl file mit dem Namen MyRemoteService.aidl
Aus dieser AIDL File erstellt der Builder von Eclipse in den Ordner gen die Java Klasse zur Kommunikation mit dem Systemen.
Im nächsten Step registrieren wir den Service in der App. Andernfalls kann das ganze Programm nicht mit der File umgehen. Also fügen wir z.B. folgendes in die AndroidManifest.xml ein.
Jetzt zur Erklärung. Ein Remoteservice wird über die Interfacefile erzeugt. Dem Remoteservice hängt aber eine Klasse an, die die angegebenen Funktionen im Interface ausführt. das wäre dann in der Zeile: android:name=”.remoteservices.MyRemoteService” Das heißt, ich hab ein neues Packages erstellt das .remoteservices heißt und hab darin die Klasse MyRemoteService erzeugt. Per Intent Filter wird anschließend die Interface .aidl Datei angegeben.
Jetzt erzeugen wir noch die Klasse zur AIDL. Es ist wie bei jedem Interface, das es einer Klasse zu Grunde liegt.
package de.jkoeber.testapp.remoteservices;
import java.util.ArrayList;
import java.util.List;
import de.jkoeber.testapp.MyRemoteService;
public class MyRemoteService extends Service {
private Handler handler = new Handler();
@Override
public void onCreate() {
super.onCreate();
ctx= this;
}
@Override
public IBinder onBind(Intent intent) {
// Return the interface
return mBinder;
}
private final MyRemoteService.Stub mBinder = new MyRemoteService.Stub() {
@Override
public void startUpate() throws RemoteException {
// start update
}
/**
* stop updating service
*/
@Override
public void stopUpdate() throws RemoteException {
// stop service
}
/**
* check if update is running
*/
@Override
public boolean isUpdating() throws RemoteException {
// check if service is running
}
};
}
Wer den Fehler: unknown option: – please use -help for a list of valid options steht erstmal vor einem Rätsel. Es ist aber ziemlich einfach. Da Android eher von Google kommt und damit auch eher die Unix und Mac Programmierer ansprechen will stellt man sich dem dummen Windows Nutzer quer und baut schnell mal seinen AVD Manager um.
Seit der aktuelle Version des SDK und AVD Managers ist es nicht mehr gestattet mit Leerstellen im Pfad zum AVD Manager zu arbeiten.
Wer voher einen ähnlichen Pfad wie ich hatte mit Leerstelle. zum Beispiel: c:\Program Files\Android\SDK-Manager\ wird jetzt ziemlich schnell enttäuscht und man erhält den Fehler: unknown option: – please use -help for a list of valid options
Typischerweise gibt es kein Logging und somit beginnt eine dreitägige Tour der Suche in den endlosen Weiten der Updates und Reinstallationen um einen solch banalen Fehler zu finden. Für alle anderen die den Fehler auch haben und sich Emulatoren nicht mehr vernünftig starten lassen. Ladet euren SDK Manager in ein Verzeichnis ohne Leerstellen: c:\android\sdk-manager\ und schon funktoiniert es wie gehabt.
Heute geht es um die Orientation im Android. Alle oder so gut wie alle aktuellen Smartphonehandys haben einen Sensor um die Ausrichtung des Handybildschirms zu bestimmen. Landscape oder Portrait heißen diese 2 Varianten. Mit diesen beiden Möglichkeiten lässt sich viel anstellen. Man kann seine Apps den größen der Monitore etc. anpassen. Eine super Sache. Aber wie stelle ich am geschicktesten die Orientation fest um vernünftig meine Programmdaten zu übergeben.
Eines ist mir aufgefallen. Pads und Handys sind zwei paar Schuhe, das aber auch die Hersteller an sich nicht an die Standards halten finde ich unverschämt. So gibt das Acer Iconia Tab andere Daten als das HTC Desire HD zurück um seine Orientation Punkte zu merken. Zur Erinnerung in der Google bzw. Android Dokumentation:
“unspecified“
The default value. The system chooses the orientation. The policy it uses, and therefore the choices made in specific contexts, may differ from device to device.
“landscape“
Landscape orientation (the display is wider than it is tall).
“portrait“
Portrait orientation (the display is taller than it is wide).
“user“
The user’s current preferred orientation.
“behind“
The same orientation as the activity that’s immediately beneath it in the activity stack.
“sensor“
The orientation determined by a physical orientation sensor. The orientation of the display depends on how the user is holding the device; it changes when the user rotates the device.
“nosensor“
An orientation determined without reference to a physical orientation sensor. The sensor is ignored, so the display will not rotate based on how the user moves the device. Except for this distinction, the system chooses the orientation using the same policy as for the “unspecified” setting.
Jeder der einzelnen Werte wird über eindeute Integer zugeordnet. Aber bei Herstellern, wie ich feststellen musste gibt es diesen Standard nicht und sie übergeben was sie wollen. Im normalen Verfahren, kann man die Position bzw. Orientierung des Displays mit diesem Befehl feststellen und dem entsprechen darauf reagieren:
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
int orientation = display.getOrientation();
Anschließend könnte man den übergebenen Wert per ActivityInfo verlgeichen und den dementsprechenden Content laden. Zum Beispiel so:
switch (orientation) {
case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
... do anything ...
break;
case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
... do anything else ...
break;
}
Aber das funktioniert nur bedingt. Für Tablet, z.B. dem Iconia von Acer gilt der Landscape und Portrait Bereich nicht, da Acer als Tab sich den Portrait Bereich im Querformat vorstellt und somit die Variable für Landscape und Portrait vertauscht. Somit bekommt man ein 0 für Landscape und 1 für Portrait was nicht sein dürfte.
Für mich ist der Landscape Modus das Querformat des Monitors und nicht die Hochkanvariante. Somit prüfe ich folgendes ab:
setContentView(R.layout.demo) // Für alle Ansichten muss der selbe Name verwendet werden
LinearLayout contentLand = (LinearLayout) findViewId(R.id.content);
LinearLayout contentPortrait = (LinearLayout) findViewId(R.id.content);
if(contentLand != null) { // check if Orientation == Landscape
... do whatever u want ...
} else if(contentPortrait != null ) { // check if Orientation == Portrait
... do whatever u want ...
}
Mein Beispiel ist kurz und knapp, ich verwende keine Mühe mehr daran den Sensor zu ermitteln wie er gerade steht sondern überlass es dem System. Ich prüfe lediglich ab welche View existiert und arbeite damit weiter. Wenn die jeweilige View ansprechbar ist bzw. in meinem Fall not null erhalte ich das selbe, für mich sogar bessere Ergebnis als wenn ich umständlich mit den Orientation Funktionen arbeite.
Ich hoffe es hilf einigen von euch die sich damit erst beschäftigen werden.