IBS Helpdesk

Professionelle IT-Lösungen

Magento Frontend deaktivieren

Standardmäßig kann man einen Magento-Shop zwar in den Wartungsmodus schicken, jedoch wird damit auch das Backend deaktiviert. Möchte man nur das Frontend deaktivieren, setzt man dies am besten per PHP um. Hierfür sind ein paar kleine Änderungen an der index.php notwendig.

Zuerst benutzt man eine Funktion namens curPageURL um die aufgerufene URL zu lesen. Die Funktion setzt man am besten unter den auskommentierten Kopf der index.php:

1
2
3
4
5
6
7
8
9
10
11
12
// Holt die aufgerufene URL
function curPageURL() {
  $pageURL = 'http';
  if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";}
  $pageURL .= "://";
  if ($_SERVER["SERVER_PORT"] != "80") {
    $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
  } else {
    $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
  }
  return $pageURL;
}

Direkt darunter folgt die Funktion zur Validierung des aufgerufenen Links:

1
2
3
4
5
6
// Prüft ob eine Textpassage in einem Link vorkommt
function verifyLink($urlpart) {
  $url = curPageURL();
  $contains = strpos($url, $urlpart);
  return $contains;
}

Vor der Zeile “if (file_exists($maintenanceFile)) {” fügt man nun den Aufruf von verifyLink(…) ein:

1
2
3
4
5
6
7
// Prüfen ob ein korrekter Backend-Link aufgerufen wurde,
// wenn nicht, einen Fehler anzeigen.
$urlpart   = '/admin/';
if (!verifyLink($urlpart)) {
  include_once dirname(__FILE__) . '/errors/404.php';
  exit;
}

Der Funktion wird in diesem Beispiel der String “/admin/” übergeben. Ruft der Benutzer also eine Seite auf, die nicht zum Adminbereich (http://test.de/index.php/admin) gehört (z.B.: “http://test.de/index.php”) erhält er als Antwort die Standard 404-Seite:

VirtualboxVM Klonen

Virtualbox ist eine hervorragendes Tool zur Desktopvirtualisierung. Möchte man gerne eine VM klonen, kann man dies über “Appliance exportieren” und “Appliance importieren” erledigen. Leider dauert dieser Vorgang ziemlich lange. Eine schnellere Methode wird hier beschrieben.

Unter Windows öffnet man im Explorer das Verzeichnis “C:\Users\[Benutzername]\VirtualBox VMs”. Hier befindet sich ein Ordner mit Namen der VM. Diesen Ordner kopiert man und benennt ihn nach der gewünschten neuen VM. Z.b.: “opensuse11.4-clone”. In diesem Ordner löscht man alle Dateien ausser der virtuellen Festplatte (Z.b.: opensuse-11.4.vdi). Wichtig: Sollte man Sicherungspunkte in der VM erstellt haben, muss man vor Schritt 1 die Sicherungspunkte entfernen. Eine Anleitung findet sich hier im Unterpunkt “Merge source snapshots”. Jede virtuelle Festplatte hat bei Virtualbox eine UUID. Dies ist eine einzigartige ID für jede Virtuelle Festplatte. Bevor man eine neue VM erstellen kann, muss man diese UUID ändern. Dies geht mit einem einfachen Befehl:

1
2
3
C:\Users\[Benutzername]>"c:\Program Files\Oracle\VirtualBox\VBoxManage.exe" int
ernalcommands sethduuid "c:\Documents and Settings\[Benutzername]\VirtualBox VM
s\openSUSE-11.4-clone\openSUSE-11.4-clone.vdi"

Jetzt legt man eine neue VM an und wählt währendessen die gerade angelegte Festplatte aus. Man sollte jedoch die kopierte VM vorher ausschalten um Namenskollisionen im Netzwerk zu vermeiden. Anmerkung: Sollte man beim starten der VM die Meldung “Waitung for device … to appear” erhalten, muss man mit einer DVD booten (zum Beispiel openSUSE-GNOME Live) und die ID der neuen Festplatte in die Datei “/boot/grub/menu.lst” auf der Festplatte eintragen. Dazu mountet man nach dem Start der Live-CD die Festplatte mit:

1
2
su
mount /dev/sda2 /mnt

Die Datei findet man dann unter “/mnt/boot/grub” und die neuen IDs der Festplatten unter “/dev/disk/by-id/ata-…”.

In der Datei müssen drei Einträge aktualisiert werden (zweimal “…part2″ und einmal “…part1″). Danach sollte die geklonte VM wie gewohnt starten.

Mehrere Thunderbird-Instanzen mit verschiedenen Profilen starten

Wie kann ich mehrere Thunderbird-Instanzen starten um bspw. geschäftliche und private Mails zu trennen?

Ganz einfach! Das Stichwort lautet: “Profile”. Hängen Sie (bspw. in der Verknüpfung Ihres Thunderbirds) folgende Parameter an und verwenden Sie dabei verschiedene Profilnamen. Legen Sie verschiedene Verknüpfungen für Ihre Profile an! Danach können Sie Add-Ons und Konfiguration völlig individuell einstellen.

...\thunderbird.exe -no-remote -p <profilname>

(Der Parameter -no-remote sorgt dafür, dass Thunderbird mehrfach gestartet werden kann)

JFormattedTextfield: Display double values as time format

Here you can find a Formatter-Implementation which is able to format double values in JFormattedTextfield as time format like “01:30″ and vice versa, i.e. needed for duration inputs. Furthermore you don’t need to input the :-separator, “0130″ will be automatically translated to “01:30″ . The formatter is also able to allow ‘native’ double inputs like “1.5″ or even “1,5″.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import java.text.ParseException;
import javax.swing.text.DefaultFormatter;
 
/**
 * <p>
 * This format converts a double value into a time format like 10:30 and vice versa.
 * </p>
 * <p>
 * Furthermore it checks if the input string<br />
 * a) can be assumed as time format without :-separator ("1030" -> 10:30)<br />
 * or<br />
 * b) is parseble as 'native' double value (like "0.5" = 00:30). It allows also inputs like "1,5".
 * </p>
 * 
 * @author denis[@]ibs-aachen.de
 */
public class DoubleTimeFormatter extends DefaultFormatter {
	private static final long serialVersionUID = -60169060463898543L;
 
	@Override
	public Object stringToValue(String string) throws ParseException {
		string = string.replace(',', '.');
 
		if (string.length() == 4) {
			try {
				Integer.parseInt(string); // check that it does only contain numbers
				String newString = string.substring(0, 2);
				newString += ":";
				newString += string.substring(2, 4);
				string = newString;
			} catch (NumberFormatException e) {
				// not possible/necessary to manipulate string to time-format
			}
		}
 
		Double d;
		try {
			d = Double.parseDouble(string);
			return d;
		} catch (NumberFormatException e) {
			// continue trying to parse time-format
		}
 
		d = new Double(0.);
		if (string.contains(":")) {
			String[] parts = string.split("[:]");
			if (parts.length > 0) {
				d += ("".equals(parts[0].trim()) ? 0 : Integer.parseInt(parts[0].trim()));
			}
			if (parts.length == 2) {
				d += ("".equals(parts[1].trim()) ? 0 : Integer.parseInt(parts[1].trim()) / 60.);
			}
		} else {
			d += ("".equals(string.trim()) ? 0 : Integer.parseInt(string.trim()));
		}
		return d;
	}
 
	@Override
	public String valueToString(Object value) throws ParseException {
		if (value == null) {
			return "";
		}
		StringBuffer toAppendTo = new StringBuffer();
		try {
			Double d = (Double) value;
			int n = d.intValue();
			toAppendTo.append(String.format("%02d:%02d", n, (int) ((d - n) * 60)));
		} catch (ClassCastException e) {
			throw new NumberFormatException("Need double value!");
		}
		return toAppendTo.toString();
	}
}

Add it to your textfield like this:

1
JFormattedTextField textfield = new JFormattedTextField(new DoubleTimeFormatter());

Feedback appreciated ;o)

Windows 7: Im Windows-Explorer die Baum-Struktur mit dem Ordnerinhalt verknüpfen

Im Windows-Explorer von Windows 7 ist die Baumstruktur auf der linken Seite standardmäßig nicht mehr mit dem Verzeichnisinhalt rechts synchron.

Wer dieses Verhalten wieder herstellen möchte, muss im Registrierungseditor folgenden Eintrag anlegen:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\
Advanced\NavPaneExpandToCurrentFolder = 1 (REG_QWORD)

Eclipselink, MS SQL Server & @@IDENTITY

When you are using the Eclipselink JPA implementation with a replicated MSSQL database (or a database with more complex triggers on some tables) you’re running probably into major problems when persisting objects, especially when you would like to use the cascaded persisting mechanism. Sometimes the database returns a wrong generated primary key which results in a foreign key constraint violation.

Reason is, that Eclipselink internally uses the query

SELECT @@IDENTITY

to fetch the generated primary key. The database uses this field to memorize the last generated ID but, and that’s the point, it doesn’t matter in which table the insert statement is been executed.

Let’s see an example:
You have a table T1 on which you defined a trigger. This trigger inserts a record into table T2.
Now, you insert your record into T1 and expect to find the generated ID of the inserted record in @@IDENTITY. But you won’t. Because of the trigger, which inserted a new record into T2, you’ll find the generated ID of T2 in @@IDENTITY.

Therefore you should use one of those methods to get the newly generated ID when you’re extensively working with triggers or the like:

SELECT SCOPE_IDENTITY()
-- OR
SELECT IDENT_CURRENT('tablename')

SCOPE_IDENTITY returns the last generated id in the same scope, whereby a scope is a stored procedure, trigger, function, or batch. IDENT_CURRENT returns the last generated id for the specified table.

Since you know in which table your record has been inserted the most secure way to fetch the id is to use IDENT_CURRENT, imho.

See some further links:
http://msdn.microsoft.com/en-us/library/ms187342.aspx
http://msdn.microsoft.com/en-us/library/ms190315.aspx
http://msdn.microsoft.com/en-us/library/ms175098.aspx

But how to fix this issue in Eclipselink?

You can implement a custom sequence strategy which uses the new query and attach this strategy to your entities. In my implementation I use the old mechanism (with @@IDENTITY) as fall-back-solution if there is no custom sequence strategy specified to an entity.

Here’s some code. First of all you need to implement the custom sequence.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package de.ibs.persistence.sequencing;
 
import org.eclipse.persistence.queries.ValueReadQuery;
import org.eclipse.persistence.sequencing.NativeSequence;
 
public class IdentCurrentSequence extends NativeSequence {
 
 public IdentCurrentSequence() {
 super();
 }
 
 // ... all other constructors
 
 @Override
 public ValueReadQuery getSelectQuery() {
 String query = "SELECT IDENT_CURRENT('#tablename#')";
 query = query.replaceFirst("(#tablename#)", this.getName().substring(9));
 return new ValueReadQuery(query);
 }
}

To declare the new sequences (one for each table), I use a separate SessionCustomizer class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package de.ibs.persistence.sequencing;
 
import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.sessions.Session;
 
public class IdentCurrentSessionCustomizer implements SessionCustomizer {
 
 public void customize(Session session) throws Exception {
 String[] identCurrentSequences = {
 "CUST_SEQ_tdtaLagerTransfer",
 "CUST_SEQ_trelServiceArtikel"
 };
 
 for (int i = 0; i<identCurrentSequences.length; i++) {
 IdentCurrentSequence sequence = new IdentCurrentSequence(identCurrentSequences[i]);
 session.getLogin().addSequence(sequence);
 }
 }
}

This IdentCurrentSessionCustomizer has to be published to the persistence unit so that it can be used.

properties.put(PersistenceUnitProperties.SESSION_CUSTOMIZER, "de.ibs.persistence.sequencing.IdentCurrentSessionCustomizer");

or in XML:

<property name="eclipselink.session.customizer" value="de.ibs.persistence.sequencing.IdentCurrentSessionCustomizer"/>

To use the sequences, add following to your entities:

1
2
3
4
5
6
7
8
9
10
@Entity
@Table(name = "tdtaLagerTransfer")
@SequenceGenerator(name="CUST_SEQ_tdtaLagerTransfer", sequenceName="CUST_SEQ_tdtaLagerTransfer")
public class LagerTransfer extends ExtendedModel implements Serializable {
 @Id
 @GeneratedValue(generator="CUST_SEQ_tdtaLagerTransfer")
 private Integer idLagerTransfer;
 
 // ... other fields and methods
}

See also:
http://wiki.eclipse.org/EclipseLink/Examples/JPA/CustomSequencing

Certainly you can implement this more clean that I did it when you understand the problem we’re facing here.

I would be delighted to hear some feedback from you.

Servervirtualisierung mit openSuse11.1 und XEN

In diesen zwei Artikeln wird beschrieben, wie man eine kostenlose Servervirtualisierung mit openSuse11.1 installiert und einrichtet.

Diese Lösung wurde auf einem ASUS Maiboard getestet (DSEB-DG) und dort traten Probleme auf, weswegen wir uns für SELS10 SP2 entschieden haben. Dieses System läuft problemlos und die vorhandene Beschreibung ist auf SELS10 anwendbar.

Die Fehler traten (meiner Meinung nach) nur wegen dieser besonderen Kombination von openSuse 11.1, diesem Raid-System und diesem Mainboard auf.

Servervirtualisierung mit XEN

Erstellung und Einrichtung eines vHosts mit XEN

MySQL root Passwort vergessen

Kann jedem mal passieren… Hier eine Anleitung für Windows-Server:

1. mysql-Dienst stoppen
service mysql stop

2. Wenn MySQL down ist, MySQL wie folgt starten

mysqld-nt --skip-grant-tables

ACHTUNG: Hierbei werden die Zugriffsrechte umgangen, so dass ALLE Benutzer VOLLEN Zugriff auf ALLE Tabellen erhalten!

3. Jetzt kann man sich als root ohne Passwort einloggen

mysql -uroot mysql

4. Im MySQL command line prompt folgende Kommandos eingeben

UPDATE user SET password=PASSWORD("newpw") WHERE user="root";
FLUSH PRIVILEGES;

5. Hierbei wird das root Passwort auf “newpw” gesetzt, mit dem man sich dann einloggen kann

mysql -uroot -pnewpw mysql

6. Nicht vergessen, MySQL-Dienst zu stoppen und wieder im normalen Modus zu starten!

Linux – Zeichenkette in Dateiinhalt suchen

Linux-Befehl, um eine Zeichenkette in Dateiinhalten (Verwendung von Wildcards im Dateinamen) im aktuellen und allen Unterverzeichnissen zu suchen:

find . -name “*.html” -exec grep -Hn “searchstring” {} \; > result.txt

Bildschirmauflösung Ubuntu 8.04+

Problem:
Nach der Installation von Ubuntu 8.04+ steht lediglich eine maximale Bildschirmauflösung von 800×600 Pixel zur Verfügung.

Lösung:
Ubuntu 7.10 von CD starten und die Datei /etc/X11/xorg.conf z.B. auf USB-Stick kopieren. Neu booten und die Datei /etc/X11/xorg.conf durch die alte Version vom USB-Stick ersetzen.